question: python gc doesn't collect buffer allocated by read_memory()

HATAYAMA Daisuke
2012-03-19T06:17:26Z

Hello,

I want to use read_memory() to read memory of core file of qemu-kvm
process that contains KVM guest memory. The problem is that garbage
collector never tries to collect the memory allocated during
read_memory() processing. So, for large qemu-kvm core file, doing this
leads to OOM.

I show an example, which is essentially the same as the issue I faced.

1. First, create a core file for test. The core file has buffer of
4096 bytes, which is intended to be read many times afterward.

# cat testpro.c
char buf[4096];

int main(int argc, char **argv)
{
*(char *)0 = 1;

return 0;
}

# gcc -g ./testpro.c -o testpro
# ulimit -c unlimited
# ./testpro
Segmentation fault (core dumped)
# ls core.*
core.4301

2. Second, open it with gdb.

# gdb ./testpro ./core.4301
<cut>

3. Use a python script that reads buf a lot of times, and so allocates
a lot of memory during the processing.

(gdb) shell cat testpro.py
import gdb
import gc

i = gdb.inferiors()[0]

buf = gdb.parse_and_eval('buf')

count = 100000
while count >= 0:
i.read_memory(buf.address, buf.type.sizeof)
count -= 1
(gdb) shell ps aux | head -n 1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
(gdb) shell ps aux | grep gdb | grep -v grep
root 4728 0.1 0.7 132560 14752 pts/3 S+ Mar19 0:00 gdb ./testpro ./core.4301
(gdb) source ./testpro.py
(gdb) shell ps aux | grep gdb | grep -v grep
root 4728 24.8 22.1 542500 424900 pts/3 S+ Mar19 0:37 gdb ./testpro ./core.4301

So, we see that used memory increased from 132560 KB to 542500 KB.

4. Try to trigger garbage collector, but it appears to be meaningless.

(gdb) python gc.collect()
(gdb) shell ps aux | grep gdb | grep -v grep
root 4728 23.1 22.1 542500 424904 pts/3 S+ Mar19 0:37 gdb ./testpro ./core.4301
(gdb) shell ps aux | grep gdb | grep -v grep
root 4728 22.3 22.1 542500 424904 pts/3 S+ Mar19 0:37 gdb ./testpro ./core.4301
(gdb) shell ps aux | grep gdb | grep -v grep
root 4728 22.3 22.1 542500 424904 pts/3 S+ Mar19 0:37 gdb ./testpro ./core.4301
(gdb) shell ps aux | grep gdb | grep -v grep
root 4728 22.2 22.1 542500 424904 pts/3 S+ Mar19 0:37 gdb ./testpro ./core.4301
(gdb) shell ps aux | grep gdb | grep -v grep
root 4728 22.0 22.1 542500 424904 pts/3 S+ Mar19 0:37 gdb ./testpro ./core.4301

5. Looking at referrers of the buffer returned by read_memory(), they
are all empty [], so it looks OK to me if garbage collector collects
the memory...

(gdb) shell cat testpro2.py
import gdb
import gc

i = gdb.inferiors()[0]
buf = gdb.parse_and_eval('buf')
print gc.get_referrers(i.read_memory(buf.address, buf.type.sizeof))
(gdb) source testpro2.py
[]

So, could anyone point at me if I'm wrong anyware?

If there's no alternative, I want another variant of read_memory()
that receives buffer in the 3rd argument; just like:

read_memory(address, length, buffer)