难道真的是传说中的JAVA里的BUG吗?好大的一只……高人请出手

chmask 2004-04-19 10:38:22
最近用java画图……然后传到服务器上对外发布……本机测试没有任何问题……可是传到大型机……sun10000/曙光2000等机器上运行后,发现内存狂涨,出现不能回收的问题……
进行测试发现问题出在drawString()上……每次drawString后,内存都会有规律的增加,并且不回收……直到关闭服务……
机器环境为
sun10000为solaris、jsdk1.4.0,曙光2000为aix4.3 、jsdk1.3

不知道有没有朋友遇到过这类问题?给java公司发了信,也没有什么回音……
大家能不能给点意见?或者有没有遇到这种问题的??非常急……谢谢各位的帮助
代码在这里……(PC机上是没有问题的,已经测试,但一到大型机就出问题)

// FrontEnd Plus GUI for JAD
// DeCompiled : TestDrawString.class

package chicken.map;

import java.io.*;
import java.sql.*;
import java.awt.*;
import java.awt.image.*;

import java.util.ArrayList;
import java.util.Arrays;

// Referenced classes of package chicken.map:
// CtgCovStartEnd, TestDrawString

public class TestDrawString
{

final int PICWIDTH = 910;
private int picHeight = PICWIDTH;
private int imgWidth;
final int IMGWIDTH = 700;
final int IMGHEIGHT = 10;
final int TOP = 5;
final int HEAD = 100;
final int DISTANCE = 5;
private String chr_id;
private int window_start;
private int window_end;
private int CtgCov_start;private int CtgCov_end;
private String CtgCov_type;
private int showName;
private String path;
private String name;
private Connection conn;
private Statement stat;
private ResultSet rs;
private String ctgCovName = null;

private ArrayList CtgCovList = new ArrayList();
StringBuffer linkInfo = new StringBuffer();

public TestDrawString()
{
picHeight = 0;
imgWidth = 0;
chr_id = null;
window_start = 0;
window_end = 0;
CtgCov_start = 0;
CtgCov_end = 0;
CtgCov_type = null;
path = null;
name = null;
conn = null;
stat = null;
rs = null;
}

int total_number = 3000;
float legend = (float)PICWIDTH / total_number;

public void createMap()
{
BufferedImage image = null;
image = new BufferedImage(3000, 3000, BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g = (Graphics2D) image.getGraphics();

g.setBackground(Color.white);
g.fillRect(0 , 0 , 3000, 3000);
g.setColor(Color.green);
String s = "TestDrawString";
for(int i = 0; i < total_number; i+= 15){
g.drawString(s, i, i);
}
try{
// com.sun.media.jai.codec.ImageCodec.createImageEncoder("PNG",
// new FileOutputStream(path + name + ".png"), null).encode(image);
FileOutputStream output = new FileOutputStream(path + name + ".png");
com.sun.media.jai.codec.ImageCodec.createImageEncoder("PNG", output, null).encode(image);
output.close();
}
catch (Exception e) {
System.out.println(e);
}
}

public void setName(String s)
{
name = s;
}

public void setPath(String s)
{
path = s;
}

public static void main(String args[])
{
TestDrawString chrmap = new TestDrawString();
chrmap.setName("TestDrawString");
chrmap.setPath("d:\\temp\\pic\\");
chrmap.createMap();
System.out.println("end");
}
}
...全文
111 92 打赏 收藏 转发到动态 举报
写回复
用AI写文章
92 条回复
切换为时间正序
请发表友善的回复…
发表回复
ajoo 2004-04-22
  • 打赏
  • 举报
回复
人家313fxq都告诉你了。你需要调用dispose()。
还在郁闷啥呀。

对了,你应该用createGraphics而不是getGraphics。
wuyaxlz 2004-04-22
  • 打赏
  • 举报
回复
up
game0ver12345 2004-04-22
  • 打赏
  • 举报
回复
有没有人能总结出楼主的程序的明确出错地方?

个人意见:楼主的程序完全没有出错。
Minsc79 2004-04-22
  • 打赏
  • 举报
回复
学习
19790219 2004-04-22
  • 打赏
  • 举报
回复
学习.....
wolfsquare 2004-04-22
  • 打赏
  • 举报
回复
to ajoo(聪明的一猪) :
createGraphics 和 getGraphics 最终都是调用 GraphicsEnvironment.getLocalGraphicsEnvironment().createGraphics();

建议楼主使用一个非Swing型的绘图库试试:
PJA2.4是一个由 eTeks 开发的纯 Java 绘图库,在 Java 虚拟机上运行不依赖任何系统绘图资源。JFreeChart 就做不到这一点,通常在 Windows 下开发的程序不能直接在 Linux 或 Unix 上运行,需要安装相关的资源库才能正常运行。

cql0007 2004-04-22
  • 打赏
  • 举报
回复
mark
chmask 2004-04-22
  • 打赏
  • 举报
回复
目前问题已经解决……谢谢各位的帮助!

最终联系到sun公司,确认为java的一个bug。对此我们升级了jsdk到1.4.2版……问题解决掉!!!

谢谢各位的帮助!
chmask 2004-04-22
  • 打赏
  • 举报
回复
to:do_do(do_do)

现在这个问题是,我们测试你的第一种可能,没有效果,每次强制gc内存也没有下降。
对于你的第二种假设,我们测试的时候,发现每次内存的增量衡定的……所以,我们现在比较认同你的观点,就是由于solaris的内存管理引起的问题。

你上面说到,你曾经遇到过类似的问题,并且用c++解决了,我想请教一下你解决这个问题的思路以及方法。能不能详细的给我讲解一下呢?非常感谢你的帮助。

同时我这里还有一个疑问:就是为什么只有drawString()出现这个问题?drawString与别的draw方法有什么不同吗?也希望大家能够一起探讨一下这个问题……
chmask 2004-04-22
  • 打赏
  • 举报
回复
to: ajoo(聪明的一猪) (
那就把带有dispose()的代码贴出来吧。没有dispose()明显是个bug。
贴个没bug的代码让大家看多好?
还有,你那个TestDrawString程序,是运行一次就死在循环里,还是多次运行后死掉?
========================================================================

这个,代码我就不再贴了,就是在绘图之后加加g.dispose()这个,你也应该知道的。如果你想测试,就麻烦你自己加上吧:)

to: game0ver12345(sfsfdsfdsdfsf)
对不起,我前面的说法有误……每次down掉的是服务,当然期间出现过死机的情况,对于这个原因现在不在我解决这个问题的讨论范围之内:)
不过,非常感谢与你的讨论,让我学习到很多东西:)
再次感谢
hotmanhh 2004-04-22
  • 打赏
  • 举报
回复
搞不懂,帮你顶上去是我的美德,哈哈。
Last_Dodo 2004-04-22
  • 打赏
  • 举报
回复
首先,solaris有用户线程和核线程两种。用户线程不是schedulable单元,一旦获得CPU,它将一直运行到它离开CPU(比如IO或time slice到点)。而核线程是schedulable单元,和其它进程/核线程竞争CPU。我不知道JAVA VM的线程是那种,但估计是核线程。

Unix上进程的大小是只增长不减小的,由于采用paging/swaping方法管理内存,如果进程大小没有上限,进程是不会因为太大而crash的。由于结合使用virtual memory和paging/swaping一个进程的大小并不等于它所占物理内存大小。在极端情况下一个任意大的正在运行着的进程可以只占一个page物理内存(1 page is around 4K in size)其它的如果是读写内存(比如变量)在swap里,如果是只读块(程序代码和常量)则被覆盖(需要用时才从文件page in)。而一个不占CPU的进程可能根本不占任何物理内存。所以,一台机器不会因为一个进程太大而死机(但此进程会dump core)。

进程大小的增加是因为程序调用了申请新内存块的系统调用(brk() system call),调用此system call的原因是内存管理在现有的内存地址(virtual address)内找不到合适的free memory。Unix上找自由内存的算法一般是first fit,即第一块足够大小的自由内存。所以你可能要一个byte但找回来的可能是1K(当然你用完一个byte后,在32bite OS上别人还可以用其余的1K-4byte)。如果所有的free memory块都小于你需要的内存大小,它将调用brk() system call申请以page为单位的内存块(即至少一个page)。这就是内存碎片问题,工作中我在solaris上碰到过这个问题,但用的是C++语言,所以通过改程序解决了这个问题。由于这个类问题我从Sun了解到solaris找自由内存的算法在进程巨大时完全放弃first fit而直接申请新内存,原因是内存太大时查找时间将很长,同时也意味着程序很可能有问题。Unix没有defragmentation 功能所以不提供对应的系统调用。

根据以上分析和你的测试程序以及你提供的其它情况,我觉得以下两种可能性较大:
1。g.drawString(s, i, i) 拷贝了s并且此拷贝在g变成garbage以前一直被引用而不能变成garbage被GC回收;
2。g.drawString(s, i, i) 导致内存碎片问题。

第一种可能性可以通过debugging来验证。其解决办法是把g尽早变成垃圾。

第二种可能性较难验证,但可以通过类似下面的程序来间接证明:
for(int i = 0; i < total_number; i+= 15){
{
String sCopy = s;
}
System.gc();
g.drawString(s, i, i);
}
其思路是在调用g.drawString(s, i, i)前保证有足够的自由内存。由于不明白它需要多少内存,你可能需要将sCopy弄得足够大。如果内存的增长变成String sCopy = s这一行那么一定是因为g.drawString(s, i, i)以后不再有适合于s大小的内存了,内存碎片的可能性基本上可以说是间接证明了。要解决这个问题可能困难较大,如果VM有defragmentation功能最简单(但程序会变慢许多),其它办法是找供应商fix和用别的东西代替。其实有一类GC算法是自动除碎片的(但耗内存),但java的GC没有用这种算法。

说了一大堆,希望没离题并对你有点帮助。
game0ver12345 2004-04-22
  • 打赏
  • 举报
回复
“发现内存狂涨,出现不能回收的问题”不是错误,这是JVM的策略。对于JVM的内存管理策略你不可能知道它什么时候回收垃圾。JVM决定在它结束的时候才回收垃圾这是100%允许的。

除非有别的错误,否则我不认为你的程序有错误,最多是你的程序不完美。

game0ver12345 2004-04-22
  • 打赏
  • 举报
回复
回复人: chmask(努力学java……) ( ) 信誉:100 2004-04-22 13:28:00 得分:0


to: game0ver12345(sfsfdsfdsdfsf)
对于是不是这个程序引起的死机问题,出于服务器的原因,我没有办法再去测试,但应该能够肯定是由于内存严重消耗所带来的问题。因为服务器上不断的跑有别的程序(都比较耗内存)

=====================================================

由于内存严重消耗所带来的问题?带来什么问题?是100%死机吗?还是10次有9次死机?

你难道就不能明确的说出你的问题吗?

例子:

  我每次启动这个程序后机器就死机,我的机器配置是.......

又或者 :

  我启动这个程序10次,至少有3次死机,我认为这里可能有问题....,我猜...





STARPACS 2004-04-22
  • 打赏
  • 举报
回复
ajoo 2004-04-22
  • 打赏
  • 举报
回复
那就把带有dispose()的代码贴出来吧。没有dispose()明显是个bug。

贴个没bug的代码让大家看多好?

还有,你那个TestDrawString程序,是运行一次就死在循环里,还是多次运行后死掉?

xuyiquan1981 2004-04-22
  • 打赏
  • 举报
回复
楼主的问题收益非浅,谢谢楼主!我觉得也是操作系统的问题,如果真的是这样的话,那么Java的跨平台性在这里证明有点问题哈。这个是楼主的一个发现哈
chmask 2004-04-22
  • 打赏
  • 举报
回复
to:: do_do(do_do)
非常感谢你深入的解释,
现在我们正在按你所提供的方法进行测试……

期待成功……:)
chmask 2004-04-22
  • 打赏
  • 举报
回复
to: game0ver12345(sfsfdsfdsdfsf)
对于是不是这个程序引起的死机问题,出于服务器的原因,我没有办法再去测试,但应该能够肯定是由于内存严重消耗所带来的问题。因为服务器上不断的跑有别的程序(都比较耗内存)

to: ajoo(聪明的一猪)
那个调用dispose()的方法我也早已经测试过……没有起到作用。谢谢你的提醒!

to: wolfsquare(狼平方 Swing报表工人) (

你的这个建议我们正在考虑,非常感谢你的建议:),有什么问题的话,还希望你能够给予帮助!
ajoo 2004-04-22
  • 打赏
  • 举报
回复
是啊。createGraphics和getGraphics都work,就象随地小便和到洗手间都能解决问题一样。
jdk给你提供了create,就是为了让你不必要downcast。get是backward compatibility而已。

这个问题没啥讨论的。先dispose()了,仍然出问题再说。这类gui里面出的所谓“内存泄漏”,往往都是程序员自己没有正确回收资源引起的。线程不是托管资源,你不回收,谁管你?
加载更多回复(72)

62,623

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧