JavaME - LWUIT 图像耗尽所有内存
我正在使用 LWUIT 编写 MIDlet,图像似乎占用了令人难以置信的内存量。我使用的所有图像都是 PNG 并打包在 JAR 文件中。我使用标准 Image.createImage(URL) 方法加载它们。该应用程序有许多表单,每个表单都有几个标签和按钮,但是我相当确定只有活动表单保留在内存中(我知道它不太值得信赖,但 Runtime.freeMemory() 似乎证实了这)。
该应用程序在 240x320 分辨率下运行良好,但将其移动到 480x640 并为 UI 使用适当更大的图像开始导致出现内存不足错误。该应用程序的功能之一是下载远程图像。在达到这一点之前,该应用程序似乎运行良好。下载几个 PNG 并返回主菜单后,遇到内存不足错误。当然,我研究了主菜单使用的内存量,结果非常令人震惊。它只是两个带有图像的标签和四个按钮。每个按钮都有三个图像,分别用于 style.setIcon、setPressedIcon 和 setRolloverIcon。图像大小范围为 15 到 25KB,但删除每个按钮使用的三个图像中的两个(因此总共 8 个图像),Runtime.freeMemory() 显示内存使用量惊人地减少了 1MB。
在我看来,我要么有很多内存泄漏(我不认为我这样做,但内存泄漏并不完全已知可以轻易追踪),我在图像处理上做了一些非常错误的事情,或者确实没有问题,我只需要缩小规模。
如果有人能提供任何见解,我将不胜感激。
I'm writing a MIDlet using LWUIT and images seem to eat up incredible amounts of memory. All the images I use are PNGs and are packed inside the JAR file. I load them using the standard Image.createImage(URL) method. The application has a number of forms and each has a couple of labels an buttons, however I am fairly certain that only the active form is kept in memory (I know it isn't very trustworthy, but Runtime.freeMemory() seems to confirm this).
The application has worked well in 240x320 resolution, but moving it to 480x640 and using appropriately larger images for UI started causing out of memory errors to show up. What the application does, among other things, is download remote images. The application seems to work fine until it gets to this point. After downloading a couple of PNGs and returning to the main menu, the out of memory error is encountered. Naturally, I looked into the amount of memory the main menu uses and it was pretty shocking. It's just two labels with images and four buttons. Each button has three images used for style.setIcon, setPressedIcon and setRolloverIcon. Images range in size from 15 to 25KB but removing two of the three images used for every button (so 8 images in total), Runtime.freeMemory() showed a stunning 1MB decrease in memory usage.
The way I see it, I either have a whole lot of memory leaks (which I don't think I do, but memory leaks aren't exactly known to be easily tracked down), I am doing something terribly wrong with image handling or there's really no problem involved and I just need to scale down.
If anyone has any insight to offer, I would greatly appreciate it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
移动设备的内存通常非常低。所以你必须使用一些技巧来节省和使用内存。
我们的一个项目也遇到了同样的问题,我们是这样解决的。
对于下载的图像:
在放置图像的地方创建一个缓存。如果您需要图像,请检查它是否在缓存映射中,如果没有,请下载并将其放在那里,如果是,请使用它。如果内存已满,请删除缓存映射中最旧的图像,然后重试。
对于其他资源图像:
只要您能看到它们,就将它们保留在内存中,如果您看不到它们,请中断引用,gc 将为您进行清理。
希望这有帮助。
Mobile devices are usually very low on memory. So you have to use some tricks to conserve and use memory.
We had the same problem at a project of ours and we solved it like this.
for downloaded images:
Make a cache where you put your images. If you need an image, check if it is in the cachemap, if it isn't download it and put it there, if it is, use it. if memory is full, remove the oldest image in the cachemap and try again.
for other resource images:
keep them in memory only for as long as you can see them, if you can't see them, break the reference and the gc will do the cleanup for you.
Hope this helps.
这里可能会发生一些事情:
确保您的模拟器使用 JRE 1.6 作为支持 JVM。如果您需要它来使用 erlyer JDK 中的运行时库,请使用
-Xbootclasspath:
。然后,在您的应用程序进入您想要看到的状态后,执行
%JAVA_HOME%\bin\jmap -dump:format=b,file=heap.bin
(如果您不这样做)如果不知道进程的 ID,请使用jps
)现在您已经获得了 JVM 堆的转储。你可以用
jhat
(JDK自带的,有点难用)或者一些第三方分析器(我更喜欢YourKit
- 它是商业的,但他们有时间)来分析它-有限的评估许可证)There are a few things that might be happening here:
Make sure that your emulator uses JRE 1.6 as backing JVM. If you need it to use the runtime libraries from erlyer JDK, use
-Xbootclasspath:<path-to-rt.jar>
.Then, after your application gets in the state you want to see, do
%JAVA_HOME%\bin\jmap -dump:format=b,file=heap.bin <pid>
(if you don't know the id of your process, usejps
)Now you've got a dump of the JVM heap. You can analyze it with
jhat
(comes with the JDK, a bit difficult to use) or some third party profilers (my preference isYourKit
- it's commercial, but they have time-limited eval licenses)我在 Java DTV 的 LWUIT 中遇到了类似的问题。当您不再需要图像时,您是否尝试刷新图像(getAWTImage().flush())?
I had a similar problem with LWUIT at Java DTV. Did you try flushing the images when you don't need them anymore (getAWTImage().flush())?
尽可能使用
EncodedImage
和资源文件(资源文件默认使用EncodedImage
。请阅读 javadoc 。其他注释也正确,您需要实际观察内存量,即使是高 RAM Android/iOS 设备,在处理多个图像时也会很快耗尽内存。避免缩放,从而有效消除
EncodedImage
。Use
EncodedImage
and resource files when possible (resource files useEncodedImage
by default. Read the javadoc for such. Other comments are also correct that you need to actually observe the amount of memory, even high RAM Android/iOS devices run out of memory pretty fast with multiple images.Avoid scaling which effectively eliminates the
EncodedImage
.您是否想到过这样一个事实:可能多次从 JAR 加载相同的图像会导致创建许多单独的图像对象(具有相同的内容),而不是为每个图像重用一个实例?这是我的第一个猜测。
Did you think of the fact, that maybe loading the same image from JAR, many times, is causing many separate image objects (with identical contents) to be created instead of reusing one instance per-individual-image? This is my first guess.