- 浏览: 3063905 次
- 性别:
- 来自: 海外
-
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
国庆假期玩得晕晕乎乎的,就不写啥硬核文了,来点轻松点的,顺带标题党+忽悠党一把 ^ ^
一段看似很无辜的C#测试代码:
编译,在桌面32位CLR 2上运行没问题。但是把几乎一样的逻辑“移植”到Java,
用Sun的32位JDK 6编译,执行,却出现
咋了,这两段代码不是几乎一样的么,怎么Java版就会出错呢?
你可以高呼:啊啊啊,Java(或者说HotSpot VM)太差劲啦!!
不过事实是:你只是被忽悠了而已。
语言规范与VM规范都不能保证解决所有现实问题。这里遇到的就是特定于实现的问题。
先看看忽悠的部分——表象。C#版代码被编译为MSIL后,Main方法的字节码是:
Java版代码被编译为字节码后为:
两者基本上是一致的,下面每行代码的意义都对应:
注意到两个版本中8*1024都被常量折叠为8192了。
主要区别有两点,其实都没多少影响:
1、微软的C#编译器为for循环生成的代码是将检查条件放在循环末尾,而在循环体开头处用一个无条件跳转指令跳到循环条件处;Sun的Java编译器则是将循环条件放在循环体开头处,在循环末尾放无条件跳转。请注意,字节码中的控制流与最终JIT出来的机器码中的控制流形式未必相同。
2、虚拟机的虚拟架构有细节上的差异。CLI将参数与局部变量区别看待,C#版的变量arrays位于局部变量的第一个槽里(local 0),变量i位于第二个槽里(local 1);JVM则把参数与局部变量都放在“局部变量区”,则main的参数args位于局部变量的第一个槽里(local 0),变量arrays位于第一个槽里,变量i位于第二个槽里;因此虽然字节码的load/store参数看似不同,实际上意思是一样的。另外,MSIL里指令通常不带类型(除加载常量、转换类型等的指令外),而JVM字节码多数指令带有类型;这个其实影响不大,意思还是保持一致的。还有的话就是C#的byte实际对应到无符号的uint8,而Java的byte对应到的是带符号的int8,在这个例子里也没什么影响。
OK,C#版代码与Java版源代码看起来几乎一样,而编译出来得到的字节码也基本一致,那还有啥问题呢?悬念继续留着,看看规范里关于“堆空间”的说明。C#与Java的规范中都没有提到“堆”到底有多大,而每个对象到底会占用多少空间;只是说当需要在堆上分配空间却没有足够剩余空间时会抛出OutOfMemoryException/OutOfMemoryError(统称OOM吧)。CLI与JVM的规范里同样没有规定堆的大小和对象占用空间的大小。概念上说,堆空间可以看成是无限大小的、无序的大块存储空间。实际运行程序时,对象占用空间的大小是虚拟机的实现细节,而有多少堆空间可用也与实现和系统配置相关。
在以前一帖里提到过32位CLR 2中int[]的内存布局。CLR的GC堆中对象按4字节边界对齐。对象header占2个DWORD:前一个位于对象起始地址-4的位置,是指向SyncBlock的索引,兼用于GC标记;后一个位于对象起始地址+0的位置,是指向该对象所属类型的MethodTable的指针。
看看本例涉及的两个数组类型的状况。
32位CLR 2中,byte[][]在内存中的布局如下:(括号中数字表示距离数组起始地址的偏移量)
所以一个byte[n][]对象占用内存大小为:4*4 + 4*n。
(开头是2个DWORD的对象header加上2个DWORD的对象数组header;后面是n个元素,每个元素都是一个DWORD;最后没有padding,因为这个大小肯定是4个倍数)
byte[]在内存中的布局如下:
所以一个byte[n]对象占用内存大小为:4*3 + 1*n + (n%4 == 0 ? 0 : 4 - n%4)。
(开头是2个DWORD的对象header加上1个DWORD的byte数组header;接着是n个元素,每个元素都是一个byte;最后是padding,填充到4字节边界)
通过SOS调试扩展的!ObjSize命令可以验证对象实际大小是否符合上文描述。
综上,在C#版的例子中,代码里显式new出来的对象至少需要占用GC堆上的这么多空间:(单位为字节)
4*4 + 4*8*1024(=32784,arrays指向的数组所占空间)
+ (4*3 + 1*8*1024 + 0)(=8204,arrays里每个元素指向的数组所占空间) * 8*1024
------------------------
= 67239952
这个大小约等于64.125MB。显然,CLR的其它一些地方也需要用到GC堆上的空间。既然C#版例子能正常完成测试,说明运行该例子时GC堆要有64MB以上。
换到Java版例子。32位JDK 6的HotSpot VM中,Java对象按8字节对齐。对象header占两个DWORD:前一个位于对象起始地址+0的位置,是一个markOop,用于记录对象的hash、“年龄”、锁状态等信息;后一个位于对象起始地址+4的位置,是指向类型信息的指针。大致看来跟CLR的对象header挺像的。
看看本例涉及的两个数组类型的状况。
在32位的HotSpot VM version 14.0(JDK 6u14开始使用)中,byte[][]在内存中的布局如下:
所以byte[n][]对象占用的内存大小为:4*3 + 4*n + ((n+3) % 2 == 0 ? 0 : 4)。
(开头是2个DWORD的对象header加上1个DWORD的对象数组header;接着是n个元素,每个元素是一个DWORD;最后是padding,填充到8字节边界)
byte[]在内存中的布局如下:
所以byte[n][]对象占用的内存大小为:4*3 + 1*n + ((n-4)%8 == 0 ? 0 : 8 - (n-4)%8)。
(开头是2个DWORD的对象header加上1个DWORD的对象数组header;接着是n个元素,每个元素是一个DWORD;最后是padding,填充到8字节边界)
要如何验证上文描述的对象大小计算公式是否正确呢?幸好,从Java 5开始有JVMTI支持,有java.lang.instrument.Instrumentation接口,其中有个getObjectSize()方法可以得到对象大小。问题是要获取这个接口的实例需要点功夫。详细可以参考这篇文章:Maxim Zakharenkov: Again about determining size of Java object。有趣的是jhat报告的对象大小跟JVMTI报告的不一致,从我调试的实际情况看JVMTI的结果应该是对的。
综上,在Java版的例子中,代码里显式new出来的对象至少需要占用GC堆上的这么多空间:(单位为字节)
4*3 + 4*8*1024 + 4(=32784,arrays指向的数组所占空间)
+ (4*3 + 1*8*1024 + 4)(=8208,arrays里每个元素指向的数组所占空间) * 8*1024
------------------------
= 67272720
这个大小约等于64.156MB。加上虚拟机和标准类库内部使用的GC堆空间,要正常运行这个测试需要大于64MB的GC堆空间。测试失败,抛出了OOM,那到底是在“什么时候”抛的呢?
把测试例子的代码改为:
看到输出为8098,也就是说arrays[8097] = new byte[8*1024];都还正常执行了;此时我们在代码里显式new出来的数组一共占了66492960字节,约等于63.413MB的GC堆空间。
===========================================================================
知道了至少需要的空间大小,却还未能解释为啥C#版正常的测试移植到Java就OOM了。在C#/Java源码一级很相似,在MSIL/JVM字节码一级很相似,甚至到VM内部的某些设计还是比较相似,占用的空间也差不了多少。问题在哪里呢?
不要想靠强制GC来解决问题哦。这例子里arrays是局部变量,是个强引用,属于GC的根集合;而所有在例子中显式new出来的byte[]都被arrays引用着,也就是说它们都是“可到达”的,强制GC完全达不到释放它们的目的。
其实上面忽悠了半天,我故意省略了一点没有提:默认情况下,CLR不限制GC堆的最大大小,依赖系统或者host来限制;没有什么“启动参数”之类的东西来限定GC堆的大小,除非自己写host来限制。而HotSpot VM却有-Xmx启动参数用于指定GC堆的最大大小,在32位的version 14.0里,Windows上该参数无论是client还是server默认值都为64M。
JVM的规范里可没有提到过什么-Xmx参数。光看Java和JVM规范都无法发现这点。纯粹是实现的问题。
于是为啥OOM了呢?不是memory leak,不是哪里的代码出错了,而是纯粹在人为的限制下HotSpot真的没办法为新建对象申请空间了。
至于解决办法嘛,自然是把GC堆的最大空间设大点就行,例如设置-Xmx256m就不会出错了。
你被忽悠到了吗?呵呵,祝大家在国庆假期最后几天保持开心~
Have fun ^ ^
咦?i686么,那就是32位系统。
我是在32位XP、Java 1.6.0u11和u14上测试的,包括client和server;没有在更高版本的JVM上测试。莫非新版本的默认值又改了么……多谢回复,我得重新读一次u14之后的版本的release notes了
Umm...我不是女的,谢谢。我现在用的头像也是某漫画的男主角来的 =v=|||
呵呵,本来我刚开始写这篇的时候没打算写中间的部分……是因为正好有人碰到了把.NET程序照搬到Java那边遇到了OOM,我正好看到了问题插一腿进去分析了一下告诉他是Xmx的问题,然后想记下来。结果写的时候无聊了想忽悠……才写了中间的部分 orz
我原本是想说.NET跟Java虽然很像,但就在那么小小的细节上不同就得让迁移中的程序员头疼,杯具啊。
杯具了
居然还没睡……放假还那么刻苦啊?今晚有球赛么?
一段看似很无辜的C#测试代码:
public class TestOOM { public static void Main(string[] args) { byte[][] arrays = new byte[8*1024][]; for (int i = 0; i < arrays.Length; i++) { arrays[i] = new byte[8*1024]; } } }
编译,在桌面32位CLR 2上运行没问题。但是把几乎一样的逻辑“移植”到Java,
public class TestOOM { public static void main(String[] args) { byte[][] arrays = new byte[8*1024][]; for (int i = 0; i < arrays.length; i++) { arrays[i] = new byte[8*1024]; } } }
用Sun的32位JDK 6编译,执行,却出现
引用
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at TestOOM.main(TestOOM.java:5)
at TestOOM.main(TestOOM.java:5)
咋了,这两段代码不是几乎一样的么,怎么Java版就会出错呢?
你可以高呼:啊啊啊,Java(或者说HotSpot VM)太差劲啦!!
不过事实是:你只是被忽悠了而已。
语言规范与VM规范都不能保证解决所有现实问题。这里遇到的就是特定于实现的问题。
先看看忽悠的部分——表象。C#版代码被编译为MSIL后,Main方法的字节码是:
IL_0000: ldc.i4 0x2000 IL_0005: newarr uint8[] IL_000a: stloc.0 IL_000b: ldc.i4.0 IL_000c: stloc.1 IL_000d: br.s IL_0020 IL_000f: ldloc.0 IL_0010: ldloc.1 IL_0011: ldc.i4 0x2000 IL_0016: newarr [mscorlib]System.Byte IL_001b: stelem.ref IL_001c: ldloc.1 IL_001d: ldc.i4.1 IL_001e: add IL_001f: stloc.1 IL_0020: ldloc.1 IL_0021: ldloc.0 IL_0022: ldlen IL_0023: conv.i4 IL_0024: blt.s IL_000f IL_0026: ret
Java版代码被编译为字节码后为:
0: sipush 8192 3: anewarray #2; //class "[B" 6: astore_1 7: iconst_0 8: istore_2 9: iload_2 10: aload_1 11: arraylength 12: if_icmpge 29 15: aload_1 16: iload_2 17: sipush 8192 20: newarray byte 22: aastore 23: iinc 2, 1 26: goto 9 29: return
两者基本上是一致的,下面每行代码的意义都对应:
ldc.i4 0x2000 | sipush 8192 newarr uint8[] | anewarray #2; //class "[B" ldc.i4.0 | iconst_0 ldlen | arraylength newarr [mscorlib]System.Byte | newarray byte stelem.ref | aastore ret | return
注意到两个版本中8*1024都被常量折叠为8192了。
主要区别有两点,其实都没多少影响:
1、微软的C#编译器为for循环生成的代码是将检查条件放在循环末尾,而在循环体开头处用一个无条件跳转指令跳到循环条件处;Sun的Java编译器则是将循环条件放在循环体开头处,在循环末尾放无条件跳转。请注意,字节码中的控制流与最终JIT出来的机器码中的控制流形式未必相同。
2、虚拟机的虚拟架构有细节上的差异。CLI将参数与局部变量区别看待,C#版的变量arrays位于局部变量的第一个槽里(local 0),变量i位于第二个槽里(local 1);JVM则把参数与局部变量都放在“局部变量区”,则main的参数args位于局部变量的第一个槽里(local 0),变量arrays位于第一个槽里,变量i位于第二个槽里;因此虽然字节码的load/store参数看似不同,实际上意思是一样的。另外,MSIL里指令通常不带类型(除加载常量、转换类型等的指令外),而JVM字节码多数指令带有类型;这个其实影响不大,意思还是保持一致的。还有的话就是C#的byte实际对应到无符号的uint8,而Java的byte对应到的是带符号的int8,在这个例子里也没什么影响。
OK,C#版代码与Java版源代码看起来几乎一样,而编译出来得到的字节码也基本一致,那还有啥问题呢?悬念继续留着,看看规范里关于“堆空间”的说明。C#与Java的规范中都没有提到“堆”到底有多大,而每个对象到底会占用多少空间;只是说当需要在堆上分配空间却没有足够剩余空间时会抛出OutOfMemoryException/OutOfMemoryError(统称OOM吧)。CLI与JVM的规范里同样没有规定堆的大小和对象占用空间的大小。概念上说,堆空间可以看成是无限大小的、无序的大块存储空间。实际运行程序时,对象占用空间的大小是虚拟机的实现细节,而有多少堆空间可用也与实现和系统配置相关。
在以前一帖里提到过32位CLR 2中int[]的内存布局。CLR的GC堆中对象按4字节边界对齐。对象header占2个DWORD:前一个位于对象起始地址-4的位置,是指向SyncBlock的索引,兼用于GC标记;后一个位于对象起始地址+0的位置,是指向该对象所属类型的MethodTable的指针。
看看本例涉及的两个数组类型的状况。
32位CLR 2中,byte[][]在内存中的布局如下:(括号中数字表示距离数组起始地址的偏移量)
----------------------- | SyncBlk索引 | (-4) ----------------------- | 指向MethodTable的指针 | (+0) ----------------------- | 数组长度 Length | (+4) ----------------------- | 元素的MethodTable指针 | (+8) ----------------------- | 下标为0的元素 | (+12+4*0) ----------------------- | 下标为1的元素 | (+12+4*1) ----------------------- | ... | ----------------------- | 下标为n的元素 | (+12+4*n) ----------------------- | ... | -----------------------
所以一个byte[n][]对象占用内存大小为:4*4 + 4*n。
(开头是2个DWORD的对象header加上2个DWORD的对象数组header;后面是n个元素,每个元素都是一个DWORD;最后没有padding,因为这个大小肯定是4个倍数)
byte[]在内存中的布局如下:
----------------------- | SyncBlk索引 | (-4) ----------------------- | 指向MethodTable的指针 | (+0) ----------------------- | 数组长度 Length | (+4) ----------------------- | 下标为0的元素 | (+8+1*0) ----------------------- | 下标为1的元素 | (+8+1*1) ----------------------- | ... | ----------------------- | 下标为n的元素 | (+8+1*n) ----------------------- | ... | -----------------------
所以一个byte[n]对象占用内存大小为:4*3 + 1*n + (n%4 == 0 ? 0 : 4 - n%4)。
(开头是2个DWORD的对象header加上1个DWORD的byte数组header;接着是n个元素,每个元素都是一个byte;最后是padding,填充到4字节边界)
通过SOS调试扩展的!ObjSize命令可以验证对象实际大小是否符合上文描述。
综上,在C#版的例子中,代码里显式new出来的对象至少需要占用GC堆上的这么多空间:(单位为字节)
4*4 + 4*8*1024(=32784,arrays指向的数组所占空间)
+ (4*3 + 1*8*1024 + 0)(=8204,arrays里每个元素指向的数组所占空间) * 8*1024
------------------------
= 67239952
这个大小约等于64.125MB。显然,CLR的其它一些地方也需要用到GC堆上的空间。既然C#版例子能正常完成测试,说明运行该例子时GC堆要有64MB以上。
换到Java版例子。32位JDK 6的HotSpot VM中,Java对象按8字节对齐。对象header占两个DWORD:前一个位于对象起始地址+0的位置,是一个markOop,用于记录对象的hash、“年龄”、锁状态等信息;后一个位于对象起始地址+4的位置,是指向类型信息的指针。大致看来跟CLR的对象header挺像的。
看看本例涉及的两个数组类型的状况。
在32位的HotSpot VM version 14.0(JDK 6u14开始使用)中,byte[][]在内存中的布局如下:
----------------------- | _mark | (+0) ----------------------- | _metadata | (+4) ----------------------- | 数组长度 length | (+8) ----------------------- | 下标为0的元素 | (+12+4*0) ----------------------- | 下标为1的元素 | (+12+4*1) ----------------------- | ... | ----------------------- | 下标为n的元素 | (+12+4*n) ----------------------- | ... | -----------------------
所以byte[n][]对象占用的内存大小为:4*3 + 4*n + ((n+3) % 2 == 0 ? 0 : 4)。
(开头是2个DWORD的对象header加上1个DWORD的对象数组header;接着是n个元素,每个元素是一个DWORD;最后是padding,填充到8字节边界)
byte[]在内存中的布局如下:
----------------------- | _mark | (+0) ----------------------- | _metadata | (+4) ----------------------- | 数组长度 length | (+8) ----------------------- | 下标为0的元素 | (+12+1*0) ----------------------- | 下标为1的元素 | (+12+1*1) ----------------------- | ... | ----------------------- | 下标为n的元素 | (+12+1*n) ----------------------- | ... | -----------------------
所以byte[n][]对象占用的内存大小为:4*3 + 1*n + ((n-4)%8 == 0 ? 0 : 8 - (n-4)%8)。
(开头是2个DWORD的对象header加上1个DWORD的对象数组header;接着是n个元素,每个元素是一个DWORD;最后是padding,填充到8字节边界)
要如何验证上文描述的对象大小计算公式是否正确呢?幸好,从Java 5开始有JVMTI支持,有java.lang.instrument.Instrumentation接口,其中有个getObjectSize()方法可以得到对象大小。问题是要获取这个接口的实例需要点功夫。详细可以参考这篇文章:Maxim Zakharenkov: Again about determining size of Java object。有趣的是jhat报告的对象大小跟JVMTI报告的不一致,从我调试的实际情况看JVMTI的结果应该是对的。
综上,在Java版的例子中,代码里显式new出来的对象至少需要占用GC堆上的这么多空间:(单位为字节)
4*3 + 4*8*1024 + 4(=32784,arrays指向的数组所占空间)
+ (4*3 + 1*8*1024 + 4)(=8208,arrays里每个元素指向的数组所占空间) * 8*1024
------------------------
= 67272720
这个大小约等于64.156MB。加上虚拟机和标准类库内部使用的GC堆空间,要正常运行这个测试需要大于64MB的GC堆空间。测试失败,抛出了OOM,那到底是在“什么时候”抛的呢?
把测试例子的代码改为:
public class TestOOM { public static void main(String[] args) { byte[][] arrays = new byte[8*1024][]; for (int i = 0; i < arrays.length; i++) { try { arrays[i] = new byte[8*1024]; } catch (Throwable t) { System.err.println(i); break; } } } }
看到输出为8098,也就是说arrays[8097] = new byte[8*1024];都还正常执行了;此时我们在代码里显式new出来的数组一共占了66492960字节,约等于63.413MB的GC堆空间。
===========================================================================
知道了至少需要的空间大小,却还未能解释为啥C#版正常的测试移植到Java就OOM了。在C#/Java源码一级很相似,在MSIL/JVM字节码一级很相似,甚至到VM内部的某些设计还是比较相似,占用的空间也差不了多少。问题在哪里呢?
不要想靠强制GC来解决问题哦。这例子里arrays是局部变量,是个强引用,属于GC的根集合;而所有在例子中显式new出来的byte[]都被arrays引用着,也就是说它们都是“可到达”的,强制GC完全达不到释放它们的目的。
其实上面忽悠了半天,我故意省略了一点没有提:默认情况下,CLR不限制GC堆的最大大小,依赖系统或者host来限制;没有什么“启动参数”之类的东西来限定GC堆的大小,除非自己写host来限制。而HotSpot VM却有-Xmx启动参数用于指定GC堆的最大大小,在32位的version 14.0里,Windows上该参数无论是client还是server默认值都为64M。
JVM的规范里可没有提到过什么-Xmx参数。光看Java和JVM规范都无法发现这点。纯粹是实现的问题。
于是为啥OOM了呢?不是memory leak,不是哪里的代码出错了,而是纯粹在人为的限制下HotSpot真的没办法为新建对象申请空间了。
至于解决办法嘛,自然是把GC堆的最大空间设大点就行,例如设置-Xmx256m就不会出错了。
你被忽悠到了吗?呵呵,祝大家在国庆假期最后几天保持开心~
Have fun ^ ^
评论
21 楼
iaimstar
2009-11-05
fandayrockworld 写道
博主多大啊,掌握这么多东西,还是个女的,强!!
20 楼
RednaxelaFX
2009-10-18
mikeandmore 写道
mike-laptop% javac TestOOM.java
mike-laptop% java TestOOM
mike-laptop% uname -a
Linux mike-laptop 2.6.31-11-generic #38-Ubuntu SMP Fri Oct 2 11:55:55 UTC 2009 i686 GNU/Linux
mike-laptop% java -version
java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03)
Java HotSpot(TM) Server VM (build 14.1-b02, mixed mode)
mike-laptop% java TestOOM
mike-laptop% uname -a
Linux mike-laptop 2.6.31-11-generic #38-Ubuntu SMP Fri Oct 2 11:55:55 UTC 2009 i686 GNU/Linux
mike-laptop% java -version
java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03)
Java HotSpot(TM) Server VM (build 14.1-b02, mixed mode)
咦?i686么,那就是32位系统。
我是在32位XP、Java 1.6.0u11和u14上测试的,包括client和server;没有在更高版本的JVM上测试。莫非新版本的默认值又改了么……多谢回复,我得重新读一次u14之后的版本的release notes了
19 楼
mikeandmore
2009-10-18
mike-laptop% javac TestOOM.java
mike-laptop% java TestOOM
mike-laptop% uname -a
Linux mike-laptop 2.6.31-11-generic #38-Ubuntu SMP Fri Oct 2 11:55:55 UTC 2009 i686 GNU/Linux
mike-laptop% java -version
java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03)
Java HotSpot(TM) Server VM (build 14.1-b02, mixed mode)
mike-laptop% java TestOOM
mike-laptop% uname -a
Linux mike-laptop 2.6.31-11-generic #38-Ubuntu SMP Fri Oct 2 11:55:55 UTC 2009 i686 GNU/Linux
mike-laptop% java -version
java version "1.6.0_15"
Java(TM) SE Runtime Environment (build 1.6.0_15-b03)
Java HotSpot(TM) Server VM (build 14.1-b02, mixed mode)
18 楼
ddbird
2009-10-13
结论不稀奇,稀奇的是分析过程,不错!
17 楼
visualcatsharp
2009-10-13
我承认我被忽悠了。
16 楼
energykey
2009-10-12
楼主我瞥了一眼你左边的分类。。。被吓着了,您火星来的吧,会这么多,大部分category我连听都没听过,杯具了啊...
15 楼
energykey
2009-10-12
平时遇到过着问题,一般是把那个限制改大一点就OK了,没有深入原理,你说的这些我看的有点迷糊...不过明白你的意思。

14 楼
fanchangyong
2009-10-12
好强大啊!
13 楼
RednaxelaFX
2009-10-11
fandayrockworld 写道
博主多大啊,掌握这么多东西,还是个女的,强!!
Umm...我不是女的,谢谢。我现在用的头像也是某漫画的男主角来的 =v=|||
12 楼
fandayrockworld
2009-10-11
博主多大啊,掌握这么多东西,还是个女的,强!!
11 楼
fandayrockworld
2009-10-11
wk,博主好牛13啊,怎么练得?
10 楼
RednaxelaFX
2009-10-09
火星叔叔马丁 写道
没看之前 猜到是jvm gc64m的问题
果然猜对了
原谅我的实用主义 推理过程被我一笔带过了
果然猜对了
原谅我的实用主义 推理过程被我一笔带过了
呵呵,本来我刚开始写这篇的时候没打算写中间的部分……是因为正好有人碰到了把.NET程序照搬到Java那边遇到了OOM,我正好看到了问题插一腿进去分析了一下告诉他是Xmx的问题,然后想记下来。结果写的时候无聊了想忽悠……才写了中间的部分 orz
我原本是想说.NET跟Java虽然很像,但就在那么小小的细节上不同就得让迁移中的程序员头疼,杯具啊。
9 楼
satanest
2009-10-09
博主真厉害,微机一定学得很好吧
8 楼
EQualizer
2009-10-08
当硬核文看的
7 楼
avi2
2009-10-07
不错,看了开头,猜对了结果,没有明白过程
6 楼
liu78778
2009-10-07

5 楼
elementstorm
2009-10-07
内牛满面
刚看也觉得是参数问题
看到中间立马受到巨大的打击啊...
刚看也觉得是参数问题
看到中间立马受到巨大的打击啊...
4 楼
java.lang.Object
2009-10-07
果然够标题党的。

3 楼
Saito
2009-10-06
每天晚上学日语.. 坚持了3天了..
. .. . .. . .顺便看看ruby ..

2 楼
RednaxelaFX
2009-10-06
Saito 写道

居然还没睡……放假还那么刻苦啊?今晚有球赛么?
发表评论
-
The Prehistory of Java, HotSpot and Train
2014-06-02 08:18 0http://cs.gmu.edu/cne/itcore/vi ... -
MSJVM and Sun 1.0.x/1.1.x
2014-05-20 18:50 0当年的survey paper: http://www.sym ... -
Sun JDK1.4.2_28有TieredCompilation
2014-05-12 08:48 0原来以前Sun的JDK 1.4.2 update 28就已经有 ... -
IBM JVM notes (2014 ver)
2014-05-11 07:16 0Sovereign JIT http://publib.bou ... -
class data sharing by Apple
2014-03-28 05:17 0class data sharing is implement ... -
HotSpot Server VM与Server Class Machine
2014-02-18 13:21 0HotSpot VM历来有Client VM与Server V ... -
Java 8的lambda表达式在OpenJDK8中的实现
2014-02-04 12:08 0三月份JDK8就要发布首发了,现在JDK8 release c ... -
GC stack map与deopt stack map的异同
2014-01-08 09:56 0两者之间不并存在包含关系。它们有交集,但也各自有特别的地方。 ... -
HotSpot Server Compiler与data-flow analysis
2014-01-07 17:41 0http://en.wikipedia.org/wiki/Da ... -
基于LLVM实现VM的JIT的一些痛点
2014-01-07 17:25 0同事Philip Reames Sanjoy Das http ... -
tailcall notes
2013-12-27 07:42 0http://blogs.msdn.com/b/clrcode ... -
《自制编程语言》的一些笔记
2013-11-24 00:20 0http://kmaebashi.com/programmer ... -
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22449(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局 (0): 拿在手上的是什么
2013-11-04 18:22 21545(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
Java的instanceof是如何实现的
2013-09-22 16:57 0Java语言规范,Java SE 7版 http://docs ... -
也谈类型: 数据, 类型, 标签
2013-08-18 01:59 0numeric tower http://en.wikiped ... -
oop、klass、handle的关系
2013-07-30 17:34 0oopDesc及其子类的实例 oop : oopDesc* ... -
Nashorn各种笔记
2013-07-15 17:03 0http://bits.netbeans.org/netbea ...
相关推荐
uniapp实战商城类app和小程序源码,包含后端API源码和交互完整源码。
本课程是 PHP 进阶系列之 Swoole 入门精讲,系统讲解 Swoole 在 PHP 高性能开发中的应用,涵盖 协程、异步编程、WebSocket、TCP/UDP 通信、任务投递、定时器等核心功能。通过理论解析和实战案例相结合,帮助开发者掌握 Swoole 的基本使用方法及其在高并发场景下的应用。 适用人群: 适合 有一定 PHP 基础的开发者、希望提升后端性能优化能力的工程师,以及 对高并发、异步编程感兴趣的学习者。 能学到什么: 掌握 Swoole 基础——理解 Swoole 的核心概念,如协程、异步编程、事件驱动等。 高并发处理——学习如何使用 Swoole 构建高并发的 Web 服务器、TCP/UDP 服务器。 实战项目经验——通过案例实践,掌握 Swoole 在 WebSocket、消息队列、微服务等场景的应用。 阅读建议: 建议先掌握 PHP 基础,了解 HTTP 服务器和并发处理相关概念。学习过程中,结合 官方文档和实际项目 进行实践,加深理解,逐步提升 Swoole 开发能力。
matlab齿轮-轴-轴承系统含间隙非线性动力学 基于matlab的齿轮-轴-轴承系统的含间隙非线性动力学模型,根据牛顿第二定律,建立齿轮系统啮合的非线性动力学方程,同时也主要应用修正Capone模型的滑动轴承无量纲化雷诺方程,利用这些方程推到公式建模;用MATLAB求解画出位移-速度图像,从而得到系统在不同转速下的混沌特性,分析齿轮-滑动轴承系统的动态特性 程序已调通,可直接运行 ,关键词:Matlab;齿轮-轴-轴承系统;含间隙非线性动力学;牛顿第二定律;动力学方程;修正Capone模型;无量纲化雷诺方程;位移-速度图像;混沌特性;动态特性。,基于Matlab的齿轮-轴-轴承系统非线性动力学建模与混沌特性分析
2024年移动应用隐私安全观测报告.pdf
本电影评论网站管理员和用户。管理员功能有个人中心,用户管理,电影类别管理,电影信息管理,留言板管理,论坛交流,系统管理等。用户可以对电影进行评论。因而具有一定的实用性。本站是一个B/S模式系统,采用SSM框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得电影评论网站管理工作系统化、规范化。 本系统的使用使管理人员从繁重的工作中解脱出来,实现无纸化办公,能够有效的提高电影评论网站管理效率。 关键词:电影评论网站;SSM框架;MYSQL数据库 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关技术 2 2.1 MYSQL数据库 2 2.2 B/S结构 3 2.3 Spring Boot框架简介 4 3系统分析 4 3.1可行性分析 4 3.1.1技术可行性 4 3.1.2经济可行性 5 3.1.3操作可行性 5 3.2系统性能分析 5 3.2.1 系统安全性 5 3.2.2 数据完整性 6 3.3系统界面分析 6 3.4系统流程和逻辑 7 4系统概要设计 8 4.1概述 8 4.2系统结构 9 4.
2023-04-06-项目笔记-第四百三十六阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.434局变量的作用域_434- 2025-03-13
基于STM32的流量计智能流速流量监测、水泵报警系统(泵启动 1100027-基于STM32的流量计智能流速流量监测、水泵报警系统(泵启动、阈值设置、LCD1602、超阈值报警、proteus) 功能描述: 基于STM32F103C8单片机实现的智能流速、流量,流量计设计 实现的功能是通过信号发生器模拟齿轮传感器,检测流量的大小,同时计算流过液体的总容量 可以设置最大流过的总容量,当超过设定值后通过蜂鸣器与LED灯指示 当没有超过则启动水泵控制电路带动液体流动 1、流速检测 2、流量统计 3、阈值显示与设置(通过按键实现阈值的调节或清零) 4、水泵启动 5、超阈值报警 有哪些资料: 1、仿真工程文件 2、PCB工程文件 3、原理图工程文件 4、源代码 ,核心关键词: 基于STM32的流量计; 智能流速流量监测; 水泵报警系统; 阈值设置; LCD1602; 超阈值报警; Proteus仿真; STM32F103C8单片机; 齿轮传感器; 信号发生器; 流量统计; 蜂鸣器与LED灯指示; 水泵控制电路。,基于STM32的智能流量监测与报警系统(阈值可调、流速与流量监
(灰度场景下的平面、海底、船、受害者)图像分类数据集【已标注,约1100张数据】 数据经过预处理,可以直接作为分类网络输入使用 分类个数【4】:平面、海底、船、受害者【具体查看json文件】 划分了训练集、测试集。存放各自的同一类数据图片。如果想可视化数据集,可以运行资源中的show脚本。 图像分类、分割网络改进:https://blog.csdn.net/qq_44886601/category_12858320.html 计算机视觉完整项目:https://blog.csdn.net/qq_44886601/category_12816068.html
arkime无geo下的oui文件
人脸识别项目实战
人脸识别项目实战
CAD 2025 二次开发dll
人脸识别项目源码实战
c语言学习
基于扩张状态观测器eso扰动补偿和权重因子调节的电流预测控制,相比传统方法,增加了参数鲁棒性 降低电流脉动,和误差 基于扩张状态观测器eso补偿的三矢量模型预测控制 ,基于扩张状态观测器; 扰动补偿; 权重因子调节; 电流预测控制; 参数鲁棒性; 电流脉动降低; 误差降低; 三矢量模型预测控制,基于鲁棒性增强和扰动补偿的电流预测控制方法
c语言学习
UE开发教程与学习方法记录.zip
在智慧园区建设的浪潮中,一个集高效、安全、便捷于一体的综合解决方案正逐步成为现代园区管理的标配。这一方案旨在解决传统园区面临的智能化水平低、信息孤岛、管理手段落后等痛点,通过信息化平台与智能硬件的深度融合,为园区带来前所未有的变革。 首先,智慧园区综合解决方案以提升园区整体智能化水平为核心,打破了信息孤岛现象。通过构建统一的智能运营中心(IOC),采用1+N模式,即一个智能运营中心集成多个应用系统,实现了园区内各系统的互联互通与数据共享。IOC运营中心如同园区的“智慧大脑”,利用大数据可视化技术,将园区安防、机电设备运行、车辆通行、人员流动、能源能耗等关键信息实时呈现在拼接巨屏上,管理者可直观掌握园区运行状态,实现科学决策。这种“万物互联”的能力不仅消除了系统间的壁垒,还大幅提升了管理效率,让园区管理更加精细化、智能化。 更令人兴奋的是,该方案融入了诸多前沿科技,让智慧园区充满了未来感。例如,利用AI视频分析技术,智慧园区实现了对人脸、车辆、行为的智能识别与追踪,不仅极大提升了安防水平,还能为园区提供精准的人流分析、车辆管理等增值服务。同时,无人机巡查、巡逻机器人等智能设备的加入,让园区安全无死角,管理更轻松。特别是巡逻机器人,不仅能进行360度地面全天候巡检,还能自主绕障、充电,甚至具备火灾预警、空气质量检测等环境感知能力,成为了园区管理的得力助手。此外,通过构建高精度数字孪生系统,将园区现实场景与数字世界完美融合,管理者可借助VR/AR技术进行远程巡检、设备维护等操作,仿佛置身于一个虚拟与现实交织的智慧世界。 最值得关注的是,智慧园区综合解决方案还带来了显著的经济与社会效益。通过优化园区管理流程,实现降本增效。例如,智能库存管理、及时响应采购需求等举措,大幅减少了库存积压与浪费;而设备自动化与远程监控则降低了维修与人力成本。同时,借助大数据分析技术,园区可精准把握产业趋势,优化招商策略,提高入驻企业满意度与营收水平。此外,智慧园区的低碳节能设计,通过能源分析与精细化管理,实现了能耗的显著降低,为园区可持续发展奠定了坚实基础。总之,这一综合解决方案不仅让园区管理变得更加智慧、高效,更为入驻企业与员工带来了更加舒适、便捷的工作与生活环境,是未来园区建设的必然趋势。
VSCodeUserSetup-x64-1.98.0.rar vscode是一种简化且高效的代码编辑器,同时支持诸如调试,任务执行和版本管理之类的开发操作。它的目标是提供一种快速的编码编译调试工具。然后将其余部分留给IDE。vscode集成了所有一款现代编辑器所应该具备的特性,包括语法高亮、可定制的热键绑定、括号匹配、以及代码片段收集等。 Visual Studio Code(简称VSCode)是Microsoft开发的代码编辑器,它支持Windows,Linux和macOS等操作系统以及开源代码。它支持测试,并具有内置的Git版本控制功能以及开发环境功能,例如代码完成(类似于IntelliSense),代码段和代码重构等。编辑器支持用户定制的配置,例如仍在编辑器中时,可以更改各种属性和参数,例如主题颜色,键盘快捷键等,内置的扩展程序管理功能。
1、文件内容:highcontrast-qt5-0.1-2.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/highcontrast-qt5-0.1-2.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊