This code runs every 100 ms. The memory usage just keeps increasing until it hits 1.5 GB and then it crashes.
void takeScreenShot()
{
Surface s;
s = CaptureScreen();
pictureBox1.Image = new Bitmap(Surface.ToStream(s, ImageFileFormat.Bmp));
s.Dispose();
}
public Surface CaptureScreen()
{
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
Device device = new Device(new Direct3D(), 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.HardwareVertexProcessing, new PresentParameters(width, height));
DisplayMode disp = device.GetDisplayMode(0);
Surface s = Surface.CreateOffscreenPlain(device, disp.Width, disp.Height, Format.A8R8G8B8, Pool.Scratch);
device.GetFrontBufferData(0, s);
return s;
}
You are creating a new device every time.
You should create the device only once, create it in your startup code once and then keep using it.
Furthermore I suspect a memory leak in Surface.ToStream() the returned stream probably needs disposing too.
var stream = Surface.ToStream(s, ImageFileFormat.Bmp);
pictureBox1.Image = new Bitmap(stream);
stream.Dispose();
As Hans Passant mentioned, Bitmap needs disposing as well.
You can very easily debug memory leaks in SharpDX by a helper to make diagnostic about unreleased COM resources. Setup at the beginning of your application this variable:
SharpDX.Configuration.EnableObjectTracking = true;
When your application exit, It will a print a report of COM objects that were not properly released with the stacktrace. The class behind this is ObjectTracker.
ObjectTracker.ReportActiveObjects() can be called to print the currently used resources at runtime (even with stack trace).
Related
I'm decoding whatever the camera codec is and then always encode it to H264 and more specifically qsv if it is supported. Currently having 2 cameras to test. One is H264 encoding and one is rawvideo. The problem comes with rawvideo. The pixel format is BGR24 and scaling to NV12
I will simplify the code because it is as any other example.
avcodec_send_packet()
// while
avcodec_receive_frame()
// if frame is not EAGAIN convert BGR24 to NV12
if (_pConvertContext == null)
{
_pConvertContext = CreateContext(sourcePixFmt, targePixFmt);
}
if (_convertedFrameBufferPtr == IntPtr.Zero)
{
int buffSize = ffmpeg.av_image_get_buffer_size(targePixFmt, sourceFrame->width, sourceFrame->height, 1);
_convertedFrameBufferPtr = Marshal.AllocHGlobal(buffSize);
ffmpeg.av_image_fill_arrays(ref _dstData, ref _dstLinesize, (byte*)_convertedFrameBufferPtr, targePixFmt, sourceFrame->width, sourceFrame->height, 1);
}
return ScaleImage(_pConvertContext, sourceFrame, targePixFmt, _dstData, _dstLinesize);
And ScaleImage method
ffmpeg.sws_scale(ctx, sourceFrame->data, sourceFrame->linesize, 0, sourceFrame->height, dstData, dstLinesize);
AVFrame* f = ffmpeg.av_frame_alloc();
var data = new byte_ptrArray8();
data.UpdateFrom(dstData);
var linesize = new int_array8();
linesize.UpdateFrom(dstLinesize);
f->data = data;
f->linesize = linesize;
f->width = sourceFrame->width;
f->height = sourceFrame->height;
f->format = (int)targePixelFormat;
return f;
After that sending the scaled frame to the encoder and receiving it and writing the file. After that I call av_frame_free(&frame) on the frame returned from the method. But when I set breakpoint I can see the address of the frame is the same even after calling av_frame_alloc() and cleaning everytime. And I think this is the reason for the memory leak. If I do deep clone of the f before returning it everything is fine. Why is that happening while the same logic works fine with the other camera?
Well, after 3 lost days of trying to figure out why it happens with certain cameras only, I've made a memory dump using DebugDiag 2 with a memory leak tracker. It turned out there is tons of memory allocations by _aligned_offset_malloc as you can see in the picture below. I was using ffmpeg 4.2.2, downgrading to 4.0.2 fixed the problem for me. No memory leak now. I'm using 32bit version.
I am trying to create large number of 1 bit per pixel bmp image from base 64 string and saving. As per the requirement a very huge number of images being created in a short period of time( an average of 50,000 to 1,00,000 in a short duration). I am using the below code.
public void CreateoneBppImageAndSave(String base64ImageString,String ImagePathToSave)
{
byte[] byteArray = Convert.FromBase64String(base64ImageString);
System.Drawing.Image img = byteArrayToImage(byteArray);
Bitmap objBitmap = new Bitmap(img);
BitmapData bmpData = objBitmap.LockBits(new Rectangle(0, 0, objBitmap.Width, objBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
Bitmap oneBppBitmap = new Bitmap(objBitmap.Width, objBitmap.Height, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, bmpData.Scan0);
oneBppBitmap.Save(ImagePathToSave, ImageFormat.Bmp);
img.Dispose();
objBitmap.Dispose();
objBitmap.UnlockBits(bmpData);
oneBppBitmap.Dispose();
}
private Image byteArrayToImage(byte[] byteArrayIn)
{
using (MemoryStream ms = new MemoryStream(byteArrayIn))
{
return Image.FromStream(ms);
}
}
Here the physical memory usage going very high. Usually the images are generated with size of 200x200 to 754x1024 . After certain duration physical memory usage reaching to the extreme and out of memory exception is being thrown.The physical memory is getting increased by 0.01 GB by every 5-10 seconds. Please help me to optimize the code in terms of memory usage.
You call LockBits on objBitmap however you call UnlockBits on oneBppBitmap. You should be calling unlock on the same object you called lock on.
As for using statements like I mentioned in the comments, a using statement turns this
using(SomeType obj = new SomeType())
{
// Some code
}
in to the equivalent of this
SomeType obj = new SomeType())
try
{
// Some code
}
finally
{
obj.Dispose();
}
That guarantees that even if a exception is thrown in // Some Code the dispose action will still happen. Your code, as it is right now, will not dispose any of its objects if any of your functions between the creation and dispose throws an exception.
Here is a re-written version with all the corrections I mentioned plus a few others..
public void CreateoneBppImageAndSave(String base64ImageString,String ImagePathToSave)
{
byte[] byteArray = Convert.FromBase64String(base64ImageString);
using(Image img = byteArrayToImage(byteArray))
using(Bitmap objBitmap = new Bitmap(img))
{
BitmapData bmpData = objBitmap.LockBits(new Rectangle(0, 0, objBitmap.Width, objBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
try
{
using(Bitmap oneBppBitmap = new Bitmap(objBitmap.Width, objBitmap.Height, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, bmpData.Scan0))
{
oneBppBitmap.Save(ImagePathToSave, ImageFormat.Bmp);
}
}
finally
{
//put the unlock in a finally to make sure it happens.
objBitmap.UnlockBits(bmpData);
}
}
}
EDIT: If this really is in your code
objBitmap.Dispose();
objBitmap.UnlockBits(bmpData);
That is the source of your problem, you should not call any methods on a class after you dispose. That is another benefit of using, you can't call methods late because the variable goes out of scope when you leave the using block.
I am trying to make a small application to serve screenshot of entire screen through network. I want it to be able to serve one every 1-2 seconds through LAN. I thought it won't be a big problem, so I chose C# and nancy www self host (as the easiest option). Now, the speed is allright for my needs, but it seems to be taking way too much memory, and it grows with time. It seems to settle on taking about 3.5 GB RAM and from then no longer grows, but that's not an acceptable amount - even with big resolution (mine is 2560x1440).
Is my code bad, or is nancy not suitable for handling many big responses, or maybe C# method of capturing screen is poorly optimized and I should try pinvoke methods? Or maybe it's just a terrible way to do it and I should try something more advanced, like using VNC library?
Currently my code looks like this:
public class HomeModule : NancyModule
{
private Bitmap bitmapScreenCapture;
private Graphics graphics;
private Object lockMe = new object();
private MemoryStream memoryStream = new MemoryStream();
public HomeModule()
{
Get["image"] = parameters =>
{
lock (lockMe)
{
GC.Collect();
if (bitmapScreenCapture == null || bitmapScreenCapture.Width != Screen.PrimaryScreen.Bounds.Width || bitmapScreenCapture.Height != Screen.PrimaryScreen.Bounds.Height)
{
if (bitmapScreenCapture != null)
{
bitmapScreenCapture.Dispose();
}
bitmapScreenCapture = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
graphics = Graphics.FromImage(bitmapScreenCapture);
}
graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0, 0,
bitmapScreenCapture.Size,
CopyPixelOperation.SourceCopy);
bitmapScreenCapture.Save(memoryStream, ImageFormat.Png);
memoryStream.Position = 0;
return new Response()
{
Contents = stream => memoryStream.CopyTo(stream)
};
}
};
}
}
As much as possible, keep variables in the most local scope possible, and dispose of what you can.
Part of your issue may be that you're new'ing up a Graphics instance repeatedly, but never disposing of the old reference. The GC will collect it eventually, but you can place your code in a using block to let it know you're done with it.
I haven't tested this, but here I've made your instances local, and disposed of the Graphics and Bitmap instances. I didn't dispose of the MemoryStream since I'm not sure it will successfully return the value if you do, but you could play around with it.
var screen = Screen.PrimaryScreen;
using (var bitmap = new Bitmap(screen.Bounds.Width, screen.Bounds.Height))
{
using (var g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(screen.Bounds.Left, screen.Bounds.Top, 0, 0, screen.Bounds.Size);
}
var imageStream = new MemoryStream();
bitmap.Save(imageStream, ImageFormat.Png);
imageStream.Position = 0;
return new Response()
{
Contents = stream => memoryStream.CopyTo(stream)
};
}
Ok, in my project resources i have some images (.png). Whenever the user clicks on a Button a new image will be shown in an ImageBox. Because all of my images are stored in my project resources i have to get the Image.Source by code. I managed to do it by using a Method like this :
public void ImageSource()
{
Bitmap someImage;
BitmapSource someImageSource;
someImage= new Bitmap(Properties.Resources.Image1);
someImageSource = getBitmapSourceFromBitmap(someImage);
ImageBox.Source = someImageSource;
}
public static BitmapSource getBitmapSourceFromBitmap(Bitmap bmp)
{
BitmapSource returnSource = null;
try
{
returnSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
catch { returnSource = null; }
return returnSource;
}
In my app everything works fine. No errors , no warnings, images change fine every time i push the Button. After some monitoring in the memory , i noticed that every time i call the getBitmapSourceFromBitmap my memory explodes 100MB EVERY TIME.
Does anyone have any idea why is this happening?
Sorry for my English.
You are using unmanaged resources to create bitmap from your image. GC doesn't takes care of memory allocated to unmanaged resources. You need to dispose of your memory that you are using in that method.
After you have converted your image to bitmap you need to release all the unmanaged resources.
my memory explodes 100MB EVERY TIME
As a general statement if your memory increases by 100MB doesn't means that you have a memory leak. In case of managed resources GC will collect all the memory that is collectible whenever it will feel feasible.
Your Problem:
As stated in the MSDN
You are responsible for calling the GDI DeleteObject method to free the memory used by the GDI bitmap object
You need to change your code like this
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(1000, 1000)) {
IntPtr hBitmap = bmp.GetHbitmap();
try {
var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
finally {
DeleteObject(hBitmap)
}
}
I'm developing an application that uses a mobile device to take a photo and send it using a webservice. But after I've taken 4 photos I am getting an OutOfMemoryException in the code below. I tried calling GC.Collect() but it didn't help either. Maybe someone here could be give me an advice how to handle this problem.
public static Bitmap TakePicture()
{
var dialog = new CameraCaptureDialog
{
Resolution = new Size(1600, 1200),
StillQuality = CameraCaptureStillQuality.Default
};
dialog.ShowDialog();
// If the filename is empty the user took no picture
if (string.IsNullOrEmpty(dialog.FileName))
return null;
// (!) The OutOfMemoryException is thrown here (!)
var bitmap = new Bitmap(dialog.FileName);
File.Delete(dialog.FileName);
return bitmap;
}
The function is called by an event handler:
private void _pictureBox_Click(object sender, EventArgs e)
{
_takePictureLinkLabel.Visible = false;
var image = Camera.TakePicture();
if (image == null)
return;
image = Camera.CutBitmap(image, 2.5);
_pictureBox.Image = image;
_image = Camera.ImageToByteArray(image);
}
I suspect you are holding onto references. As a minor cause, note that dialogs don't dispose themselves when using ShowDialog, so you should be using the dialog (although I would expect GC to still collect an undisposed but non-referenced dialog).
Likewise, you should probably be using the image, but again: not sure I'd expect this to make-or-break; worth a try, though...
public static Bitmap TakePicture()
{
string filename;
using(var dialog = new CameraCaptureDialog
{
Resolution = new Size(1600, 1200),
StillQuality = CameraCaptureStillQuality.Default
}) {
dialog.ShowDialog();
filename = dialog.FileName;
}
// If the filename is empty the user took no picture
if (string.IsNullOrEmpty(filename))
return null;
// (!) The OutOfMemoryException is thrown here (!)
var bitmap = new Bitmap(filename);
File.Delete(filename);
return bitmap;
}
private void _pictureBox_Click(object sender, EventArgs e)
{
_takePictureLinkLabel.Visible = false;
using(var image = Camera.TakePicture()) {
if (image == null)
return;
image = Camera.CutBitmap(image, 2.5);
_pictureBox.Image = image;
_image = Camera.ImageToByteArray(image);
}
}
I'd also be a little cautious of the CutBitmap etc, to ensure that things are released ASAP.
Your mobile device usually does not have any memory swapping to disk option, so since you choose to store your images as bitmaps in memory rather than files on disk, you quickly consume your phone's memory. Your "new Bitmap()" line allocates a large chunk of memory, so it is very likely to throw the exception there. Another contender is your Camera.ImageToByteArray that will allocate a large amount of memory. This probably isn't large to what you're used to with your computer, but for your mobile this is gigantic
Try keeping the pictures on disk until you use them, i.e. until sending them to the webservice. For displaying them, use your built-in controls, they are probably the most memory efficient and you can usually point them to the image files.
Cheers
Nik