此页面为机器翻译。请阅读英文原文。 English

IBSurgeon 文库

如何让Firebird消耗大量内存?

有时候我们会遇到 Firebird 进程占用大量内存的情况。

以下是导致这种情况的 3 个主要原因。请注意–这些并不是建议 :) 请不要在生产环境上运行它们!

1. 将页面缓冲区设置得过高

例如,在 firebird.conf 中为 SuperServer 设置:

DefaultDbCachePages = 500000M # pages

重启 Firebird 并尝试连接–结果将出现错误消息“无法从操作系统分配内存”:

isql -user SYSDBA -pass masterkey localhost:e:\temp\blob30.fdb Statement failed, SQLSTATE = HY001 unable to allocate memory from operating system -IProvider::attachDatabase failed when loading mapping cache Use CONNECT or CREATE DATABASE to specify a database SQL>

在 SuperClassic 或 Classic 模式下,如果连接数较多且页面缓冲区数量相对较高,也会出现同样的结果,根据公式:

页面缓冲区数量 × 连接数 × 页面大小。

2. Firebird 进程大小可能因大量临时 BLOB 操作而增长

尝试运行以下脚本(不要在生产环境上运行):

create generator g1; set generator g1 to 0; execute block as declare variable blb BLOB; declare variable icnt integer; begin icnt=0; while (icnt <100000000) DO begin select cast('1234567890qwertyuiopasdfghjklzxcvbnm' as BLOB) from rdb$database into :blb; select gen_id(g1,1) from rdb$database into :icnt; end end;

或者,另一种思路的变体:

create or alter procedure BLOB_LOOP returns ( ATEXT blob sub_type text ) as begin while (true) do begin atext = '123'; suspend; end end

以下查询将耗尽所有内存(不要在生产环境上运行!):

select count(*) from blob_loop

3. 对于 Classic 和 SuperClassic,可以在 isql.exe 的连接字符串中指定较大的页面缓冲区数量,并且它将为该连接分配内存

如果页面缓冲区未在头页面中显式设置(即等于 0):

`C:\FB\30Cs>echo set list on; set stat on; select mon$page_buffers from mon$database; | isql -c 98765 /:e30 -user foo -pas bar Database: /:e30, User: FOO SQL> MON$PAGE_BUFFERS 98765 Current memory = 869314176 Delta memory = 75760 Max memory = 869334512 Elapsed time= 0.001 sec Buffers = 98765 Reads = 3 Writes = 0 Fetches = 42 SQL>

set bail on; set term ^; execute block as declare n int = 10; declare c int; declare my_password varchar(20) = ‘bar’; begin while (n>0) do begin execute statement ‘select 1 from rdb$database’ on external ’localhost:’ || rdb$get_context(‘SYSTEM’, ‘DB_NAME’) as user current_user password my_password role lpad(’’, 20, replace(uuid_to_char(gen_uuid()),’-’,’’)) into c; n = n - 1;`

end

end

^

set term ;^

set list on;

select count(distinct(t.mon$attachment_id)) as num_of_attachments, sum(t.mon$memory_used) as sum_memo_used, sum(t.mon$memory_allocated) as sum_memo_allocated

from (

select

a.mon$attachment_id

,m.*

from mon$attachments a

join mon$memory_usage m on a.mon$stat_id = m.mon$stat_id

where mon$user = current_user

) t;

=======