- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
背景信息
我用 Windows 窗体 (C#) 开发了一个桌面应用程序,用于扫描、预览和保存图像。扫描时的应用程序行为如下:
图像内存管理:可压缩图像
为了管理内存使用,我创建了一个 CompressibleImage 类,它封装了一个位图文件并在 FileStream 上读取/写入图像文件。当应用程序不再需要图像时,会将其写入文件流。当应用程序需要图像(即用户双击缩略图)时,会从流中创建一个位图文件。以下是主要的 CompressibleImage 方法:
/// Gets the uncompressed image. If the image is compressed, it will be uncompressed
public Image GetDecompressedImage()
{
if (decompressedImage == null)
{
// Read Bitmap from file stream
stream.Seek(0, SeekOrigin.Begin);
decompressedImage = new Bitmap(stream);
}
return decompressedImage;
}
/// Clears the uncompressed image, leaving the compressed one in memory.
public void ClearDecompressedImage()
{
// If Bitmap file exists, write it to file and dispose it
if (decompressedImage != null)
{
if (stream == null)
{
stream = new FileStream(FileStreamPath, FileMode.Create);
}
decompressedImage.Save(stream, format);
// The Dispose() call does not solve the issue
// decompressedImage.Dispose();
decompressedImage = null;
}
}
/// <summary>
/// Class destructor. It disposes the decompressed image (if this exists),
/// closes the stream and delete the temporary file associated.
/// </summary>
~CompressibleImage()
{
if (decompressedImage != null)
{
decompressedImage.Dispose();
}
if(stream != null)
{
stream.Close();
File.Delete(stream.Name);
stream.Dispose();
}
}
应用级别
应用程序主要在扫描方法和保存过程中使用 CompressibleImage 创建图像文件。扫描方法工作正常,基本上:
保存方法在我的机器上运行良好,其行为如下: 1. 对于每个 CompressibleImage 从流中解压缩(读取和构建)位图 2.保存图像 3.压缩图片
这是保存方法:
private void saveImage_button_Click(object sender, EventArgs e)
{
if (Directory.Exists(OutputPath) == false && File.Exists(OutputPath) == false)
{
Directory.CreateDirectory(OutputPath);
}
ListView.CheckedListViewItemCollection checkedItems = listView1.CheckedItems;
if(checkedItems.Count > 0)
{
for (int i = 0; i < checkedItems.Count; ++i)
{
int index = checkedItems[i].Index;
Bitmap image = (Bitmap)compressibleImageList.ElementAt(index).GetDecompressedImage();
try
{
image.Save(OutputPath + index.ToString() +
Module.PNG_FORMAT, ImageFormat.Png);
compressibleImageList.ElementAt(index).ClearDecompressedImage();
progressForm.Increment();
image = null;
}
catch (Exception ex) {
...
}
}
}
}
问题描述
在我的机器上,应用程序运行良好。没有内存泄漏,scan 和 save 方法以合理的内存使用率顺利完成工作(扫描 100 张纸,选择小于 < 140MB)。
问题是,当我尝试在其他机器上测试应用程序时,垃圾收集器没有释放内存,导致在两种方法执行期间以及当图像相当高(> 40)。当我尝试解压缩(读取)图像时,CompressibleImage.GetDecompressedImage() 方法中抛出了异常:
decompressedImage = new Bitmap(stream);
虽然我知道 GC 会随机清理内存,但在这种情况下它似乎甚至没有运行,实际上只有在我关闭应用程序时才会释放内存。
在类似的机器上有可能出现这种不同的行为吗?
系统信息
以下是有关测试环境的一些信息。两台机器都有:
最佳答案
不太确定你的 MemoryException,请提供完整的堆栈跟踪。
但是,我可以看出您在析构函数中犯了一个明显的错误。您不应该在析构函数中引用您的托管资源。原因是,GC 和 Finalizer 使用启发式算法来触发它们,您永远无法预测托管对象的终结器的执行顺序。
这就是为什么你应该在你的 dispose 方法中使用 'disposing' 标志,并避免在执行来自终结器时接触托管对象。
以下示例展示了实现 IDisposable 接口(interface)的一般最佳实践。引用:https://msdn.microsoft.com/en-us/library/system.idisposable.dispose(v=vs.110).aspx
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}
关于不同机器上的 C# 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30710895/
我在具有 2CPU 和 3.75GB 内存 (https://aws.amazon.com/ec2/instance-types/) 的 c3.large Amazon EC2 ubuntu 机器上运
我想通过用户空间中的mmap-ing并将地址发送到内核空间从用户空间写入VGA内存(视频内存,而不是缓冲区),我将使用pfn remap将这些mmap-ed地址映射到vga内存(我将通过 lspci
在 Mathematica 中,如果你想让一个函数记住它的值,它在语法上是很轻松的。例如,这是标准示例 - 斐波那契: fib[1] = 1 fib[2] = 1 fib[n_]:= fib[n] =
我读到动态内存是在运行时在堆上分配的,而静态内存是在编译时在堆栈上分配的,因为编译器知道在编译时必须分配多少内存。 考虑以下代码: int n; cin>>n; int a[n]; 如果仅在运行期间读
我是 Python 的新手,但我之前还不知道这一点。我在 for 循环中有一个基本程序,它从站点请求数据并将其保存到文本文件但是当我检查我的任务管理器时,我发现内存使用量只增加了?长时间运行时,这对我
我正在设计一组数学函数并在 CPU 和 GPU(使用 CUDA)版本中实现它们。 其中一些函数基于查找表。大多数表占用 4KB,其中一些占用更多。基于查找表的函数接受一个输入,选择查找表的一两个条目,
读入一个文件,内存被动态分配给一个字符串,文件内容将被放置在这里。这是在函数内部完成的,字符串作为 char **str 传递。 使用 gdb 我发现在行 **(str+i) = fgetc(aFil
我需要证实一个理论。我正在学习 JSP/Java。 在查看了一个现有的应用程序(我没有写)之后,我注意到一些我认为导致我们的性能问题的东西。或者至少是其中的一部分。 它是这样工作的: 1)用户打开搜索
n我想使用memoization缓存某些昂贵操作的结果,这样就不会一遍又一遍地计算它们。 两个memoise和 R.cache适合我的需要。但是,我发现缓存在调用之间并不可靠。 这是一个演示我看到的问
我目前正在分析一些 javascript shell 代码。这是该脚本中的一行: function having() { memory = memory; setTimeout("F0
我有一种情况,我想一次查询数据库,然后再将整个数据缓存在内存中。 我得到了内存中 Elasticsearch 的建议,我用谷歌搜索了它是什么,以及如何在自己的 spring boot 应用程序中实现它
我正在研究 Project Euler (http://projecteuler.net/problem=14) 的第 14 题。我正在尝试使用内存功能,以便将给定数字的序列长度保存为部分结果。我正在
所以,我一直在做 Java 内存/注意力游戏作业。我还没有达到我想要的程度,它只完成了一半,但我确实让 GUI 大部分工作了......直到我尝试向我的框架添加单选按钮。我认为问题可能是因为我将 JF
我一直在尝试使用 Flask-Cache 的 memoize 功能来仅返回 statusTS() 的缓存结果,除非在另一个请求中满足特定条件,然后删除缓存。 但它并没有被删除,并且 Jinja 模板仍
我对如何使用 & 运算符来减少内存感到非常困惑。 我可以回答下面的问题吗? clase C{ function B(&$a){ $this->a = &$a; $thi
在编写代码时,我遇到了一个有趣的问题。 我有一个 PersonPOJO,其 name 作为其 String 成员之一及其 getter 和 setter class PersonPOJO { priv
在此代码中 public class Base { int length, breadth, height; Base(int l, int b, int h) { l
Definition Structure padding is the process of aligning data members of the structure in accordance
在 JavaScript Ninja 的 secret 中,作者提出了以下方案,用于在没有闭包的情况下内存函数结果。他们通过利用函数是对象这一事实并在函数上定义一个属性来存储过去调用函数的结果来实现这
我正在尝试找出 map 消耗的 RAM 量。所以,我做了以下事情;- Map cr = crPair.collectAsMap(); // 200+ entries System.out.printl
我是一名优秀的程序员,十分优秀!