英文:
Memory leak issue with using device contexts
问题
以下是您要翻译的代码部分:
#include "contextcreator.h"
#include <cstring>
#include <stdio.h>
#include <shlwapi.h>
#include <typeinfo>
BYTE* createContext(int x, int y, int width, int height){
HDC hdesktop = GetDC(NULL);
HDC memDC = CreateCompatibleDC(hdesktop);
HBITMAP hbitmap = CreateCompatibleBitmap(hdesktop, width, height);
HGDIOBJ hbitmapOld = (HBITMAP)SelectObject(memDC, hbitmap);
BitBlt(memDC, 0, 0, width, height, hdesktop, x, y, SRCCOPY|CAPTUREBLT);
SelectObject(memDC, hbitmapOld);
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
GetDIBits(hdesktop, hbitmap, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
BYTE* stream = new BYTE[bmi.bmiHeader.biSizeImage];
bmi.bmiHeader.biCompression = BI_RGB;
GetDIBits(hdesktop, hbitmap, 0, bmi.bmiHeader.biHeight, (LPVOID)stream, &bmi, DIB_RGB_COLORS);
BYTE* data = new BYTE[14 + sizeof(bmi) + bmi.bmiHeader.biSizeImage];
memcpy(data + 14, &bmi, sizeof(bmi));
memcpy(&data[0] + sizeof(bmi) + 14, stream, bmi.bmiHeader.biSizeImage);
for(int i = 0; i < 14; i++){
data[i] = 0;
}
delete[] stream;
ReleaseDC(NULL, hdesktop);
DeleteDC(memDC);
return data;
}
void releaseData(BYTE* stream){
delete[] stream;
}
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from ctypes import *
import ctypes.wintypes as wintypes
import time
import os
os.add_dll_directory("C:/msys64/mingw64/bin")
mylib = cdll.LoadLibrary('C:/Users/amish_ac2c1jm/OneDrive/Documents/blahblah/libccreator.so')
create_context = mylib.createContext
create_context.argtypes = [c_int, c_int, c_int, c_int]
create_context.restype = POINTER(wintypes.BYTE)
release_stream = mylib.releaseData
release_stream.argtypes = [POINTER(wintypes.BYTE)]
release_stream.restype = None
class CaptureThread(QObject):
finished = pyqtSignal()
update_image = pyqtSignal([bytearray])
def __init__(self, x, y, w, h, parent=None):
super().__init__(parent)
self.x = x
self.y = y
self.w = w
self.h = h
self.stopthread = False
self.framenumber = 0
def run(self):
test_timer = time.time()
while not self.stopthread:
if time.time() - test_timer >= 1000/30/1000:
test_timer = time.time()
self.capture()
self.finished.emit()
def capture(self):
bmpptr = create_context(self.x, self.y, self.w, self.h)
data = bytearray(string_at(addressof(bmpptr.contents) + 0x22, 0x4))
size = int.from_bytes(data, byteorder='little', signed=False) + 0x36
data = bytearray(string_at(bmpptr, size)
release_stream(bmpptr)
data[0:2] = b'BM'
value = int.from_bytes(data[0x22:0x26], byteorder='little', signed=False)
data[2:6] = (value + 0x36).to_bytes(4, byteorder='little', signed=False)
data[6:10] = b'\x00\x00\x00\x00'
data[10:14] = b'\x36\x00\x00\x00'
with open(f"images/frame{self.framenumber}.bmp", "wb") as f:
f.write(data)
self.framenumber += 1
self.update_image.emit(data)
英文:
I'm using a combination of python and c++ to create a snapshot of a screen area and use that screenshot as part of a video feed (pixmap in a label PyQt5) as well as save the screenshot as a .bmp.. currently done at 30fps for creating a video file later. The code works to this degree so far just fine, aside from the memory leak I'm getting.
contextcreator.cpp, put into libccreator.so
#include "contextcreator.h"
#include <cstring>
#include <stdio.h>
#include <shlwapi.h>
#include <typeinfo>
BYTE* createContext(int x, int y, int width, int height){
HDC hdesktop = GetDC(NULL);
HDC memDC = CreateCompatibleDC(hdesktop);
HBITMAP hbitmap = CreateCompatibleBitmap(hdesktop, width, height);
HGDIOBJ hbitmapOld = (HBITMAP)SelectObject(memDC, hbitmap);
BitBlt(memDC, 0, 0, width, height, hdesktop, x, y, SRCCOPY|CAPTUREBLT);
SelectObject(memDC, hbitmapOld);
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
GetDIBits(hdesktop, hbitmap, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
BYTE* stream = new BYTE[bmi.bmiHeader.biSizeImage];
bmi.bmiHeader.biCompression = BI_RGB;
GetDIBits(hdesktop, hbitmap, 0, bmi.bmiHeader.biHeight, (LPVOID)stream, &bmi, DIB_RGB_COLORS);
BYTE* data = new BYTE[14 + sizeof(bmi) + bmi.bmiHeader.biSizeImage];
memcpy(data + 14, &bmi, sizeof(bmi));
memcpy(&data[0] + sizeof(bmi) + 14, stream, bmi.bmiHeader.biSizeImage);
for(int i = 0; i < 14; i++){
data[i] = 0; }
delete[] stream;
ReleaseDC(NULL, hdesktop);
DeleteDC(memDC);
return data;
}
void releaseData(BYTE* stream){
delete[] stream;
}
The python code that utilizes libccreator.so
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from ctypes import *
import ctypes.wintypes as wintypes
import time
import os
os.add_dll_directory("C:/msys64/mingw64/bin")
mylib = cdll.LoadLibrary('C:/Users/amish_ac2c1jm/OneDrive/Documents/blahblah/libccreator.so')
create_context = mylib.createContext
create_context.argtypes = [c_int, c_int, c_int, c_int]
create_context.restype = POINTER(wintypes.BYTE)
release_stream = mylib.releaseData
release_stream.argtypes = [POINTER(wintypes.BYTE)]
release_stream.restype = None
class CaptureThread(QObject):
finished = pyqtSignal()
update_image = pyqtSignal([bytearray])
def __init__(self, x, y, w, h, parent=None):
super().__init__(parent)
self.x = x
self.y = y
self.w = w
self.h = h
self.stopthread = False
self.framenumber = 0
def run(self):
test_timer = time.time()
while not self.stopthread:
if time.time() - test_timer >= 1000/30/1000:
test_timer = time.time()
self.capture()
self.finished.emit()
def capture(self):
bmpptr = create_context(self.x, self.y, self.w, self.h)
data = bytearray(string_at(addressof(bmpptr.contents) + 0x22, 0x4))
size = int.from_bytes(data, byteorder='little', signed=False) + 0x36
data = bytearray(string_at(bmpptr, size))
release_stream(bmpptr)
data[0:2] = b'BM'
value = int.from_bytes(data[0x22:0x26], byteorder='little', signed=False)
data[2:6] = (value + 0x36).to_bytes(4, byteorder='little', signed=False)
data[6:10] = b'\x00\x00\x00\x00'
data[10:14] = b'\x36\x00\x00\x00'
with open(f"images/frame{self.framenumber}.bmp", "wb") as f:
f.write(data)
self.framenumber += 1
self.update_image.emit(data)
Originally i had some memory leaks from not deleting the byte arrays created with the new keyword, and such memory leak issue was apparent quite quickly when my monitors started blinking and chrome would crash along with pycharm. I also wasn't originally using ReleaseDC for the [hardware?] DC, but instead using DeleteDC for both that DC and the memory DC. I was able to visually see the memory leak in task manager as my project very quickly overcame chrome and pycharm memory usage (these bmp's aren't compressed after all.. something I'll look into later). Still, a memory leak persists but doesn't show up for my app in task manager, only showing my overall memory usage gradually increase until i run out of memory. Takes about 7min or so (i have 16gb of RAM).
I feel it has something to do with the DC's, but i'm not entirely sure. I have some experience with c++ from a while back, but once i learned python i didn't miss compiler and linking issues to say the least lol.
I use PyCharm for my python IDE and Qt Creator for c++. Thanks in advance for any help
答案1
得分: 1
根据Igor Tandetnik的评论回复,泄漏是因为没有删除从CreateCompatibleBitmap函数返回的对象。
英文:
As per the comment response from Igor Tandetnik, the leak was from not deleting the object returned from the CreateCompatibleBitmap function.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论