处理 Swing 动画的内存
这是我第一次在那里写作,但在阅读和搜索了很多关于我要解释的主题之后,我没有找到任何对我有用的东西(我检查了一个人的帖子,解释了有关 iPhone 应用程序的类似内容,但没有最终解决方案)。抱歉我的英语我会尽力做到最好呵呵:)。
好的,我开始了:我有一个 java 应用程序,可以在 JPanel 上同时显示一组动画。这些动画是来自Animation(继承自JLabel)的java对象,这是我自己的一个类,它存储了一个ImageIcon数组(代表动画帧)和一个整数指针,显示要绘制的实际框架(索引)。 该类以这种方式重写了 setPaint() 方法:
@Override
public void paintComponent(Graphics g) {
g.drawImage(getImageAt(getCurrentIndex()).getImage(), getX2(), getY2(), getW(), getH(), null);
//getImage at retrieves the frame at a "index" position from frame array.
if (getCurrentIndex() < getTotal() - 1) {
incrementIndex();//increments frame by 1 (next frame)
} else {
resetIndex();//set index to 0 (frame 0)
}
}
另一方面,我们有 Display,它继承自 JPanel 并负责重新绘制面板(它使用 javax.swing.Timer 对象)并且每 50 毫秒重新绘制一次)。
每个动画对象的所有图像都具有相同的尺寸 768x576 和带有透明度的 png 格式(因此我可以一次绘制许多动画)。
问题是,当我加载动画时,它占用了太多内存,因为它创建了我不知道为什么除了真正占用的 2MB 之外的 200 MB 的“int”对象。当我加载更多动画时,JVM 的堆空间猛增(高达 1.7 GB...我不想再尝试 xD)。例如,6 个动画可能为 405 帧(平均 90 帧)。 我已经使用 JProfiler 收集了这些数据,但我无法发布捕获的数据,所以我得到的是: JProfiler 对我的应用程序的内存使用情况:
java.awtRectangle 3351 KB
sun.java2d.SunGraphics2D 16.510 KB (我认为这是所有动画的大小,听起来很合乎逻辑) .
java.lang.String 669KB
int[] 1337 MB ...
在显示中,加载图像的过程是这样的:
add(new Animation (loadImageSet(Constants.DIR_CINTA_EJE,"all"),
Constants.A_CINTA_EJE, 75,-200,768,576));//1
其中 DIR_CINTA_EJE 是该动画的所有帧所在的目录,值“all”意味着我要加载所有帧。
有没有办法避免内存使用随着动画数量线性增长?为什么那些“int”值占据这么多?它们是每个图像的像素吗?
是的,我已将堆空间增加到 2GB,并且可以正常工作,但成本很高。 非常感谢您提供的所有帮助。我真的很喜欢这个论坛。
问候。
It's my first time writting there but after reading and searching a lot about the subject I'm going to explain, I didn't found anything useful for me (I've checked a post of a guy explaining something similar about an iphone app, but without a final solution). Sorry for my english I'll try to do my best hehe :).
Ok, I'm starting: I have java application that shows a set of animations at the same time on a JPanel. These animations are java objects from Animation (inheritates from JLabel), a class of my own that stores an array of ImageIcon (representing the frames of animation) and an integer pointer, showing actual frame to paint (index).
That class has overriden the method setPaint() in that way:
@Override
public void paintComponent(Graphics g) {
g.drawImage(getImageAt(getCurrentIndex()).getImage(), getX2(), getY2(), getW(), getH(), null);
//getImage at retrieves the frame at a "index" position from frame array.
if (getCurrentIndex() < getTotal() - 1) {
incrementIndex();//increments frame by 1 (next frame)
} else {
resetIndex();//set index to 0 (frame 0)
}
}
On the other hand, we have Display, which inheritates from JPanel and is responsible for repainting the panel (it uses I javax.swing.Timer object and repaints every 50 ms).
All the images from every Animation object have the same size 768x576 and png format with transparencies (thus I can paint many animations at a time).
The problem is that when I load an animation it occupies too much memory because it creates I don't know why either how 200 MB of "int" objects apart of the 2MB that really occupies. When I load more animations the heap's space of the JVM rockets (up to 1.7 GB... I didn't want to try anymore xD). For example, 6 animations may be 405 frames (90 in average).
I've collected this data with JProfiler, but I can't post the capture so this what I get:
Memory usage of my app by JProfiler:
java.awtRectangle 3351 KB
sun.java2d.SunGraphics2D 16.510 KB (I think this is the size of all the animations and sounds logical).
java.lang.String 669KB
int[] 1337 MB
...
In display, the loading images process is in this way:
add(new Animation (loadImageSet(Constants.DIR_CINTA_EJE,"all"),
Constants.A_CINTA_EJE, 75,-200,768,576));//1
Where DIR_CINTA_EJE is the directory where all the frames of that animation are and the value "all" means that I want to load all the frames.
There is a way to avoid that memory used grows linearly with the number of animations? Why those "int" values occupies so much? Are they the pixels of each image?
And yes, I have Increased my heap space up to 2GB and it's working, but at a high cost.
Thank you very much for all the help you can provide. I love this forum, really.
Regards.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我一直在努力寻找满意的解决方案,终于找到了!
这就是我所做的:
类动画不再从 JLabel 继承,它只实现 ActionListener,在
actionPerformed()
方法中,我递增要为每个帧显示的帧(我使用 Timer 类)。因此,Animation 不再重写paintComponent()
方法(它适用于 DisplayPanel)。在 DisplayPanel 中,我使用三个全局变量:
现在,我重写 DisplayPanel
paintComponent()
,因此:我区分两种情况的原因,一种用于 i==0,另一种用于其余情况帧是在绘画时我看到黑色背景和动画的整个位置,所以这是我解决问题的方式。
现在,8 个 50 帧的动画每个仅占用 360 MB 内存,而不是我上次得到的 1.3 GB =)(我只绘制一张图像,这是由于合并每个动画同时打印的所有帧而产生的) 。
谢谢你,我希望这能有所帮助!
I've been working hard looking for a satisfactory solution and finally I've got it!
That's what I have done:
Class Animation does no more inheritates from JLabel it only implements ActionListener, in which
actionPerformed()
method I increment the frame to show for each one (I use Timer class). Therefore, Animation does no more overridepaintComponent()
method (it's work for DisplayPanel).In DisplayPanel, I use thre global variables:
And now, I override there the DisplayPanel
paintComponent()
, thus:The reason why I difference two cases, one for i==0 and another for the rest of frames is that on painting I saw a black background and the whole positions of the animation, so is this way that I solve the issue.
Now, with 8 animations with 50 frames each one occuppies only 360 MB of memory instead 1.3 GB I get last time =) (I only paint one image, which results from merging all the frames to be printed at the same time for each animation).
Thank you and I hope this could help!!!