一、对象在JVM中的表示: OOP-Klass模型
https://www.jianshu.com/p/424a920771a3
写的很赞。
注意:OOP-Klass是hotspot的JVM实现原理,其他JVM的实现可能不一样。、
OOP表示java实例,Klass表示class。
Klass: 包含元数据和方法信息,用来描述Java类
OOP: Ordinary Object Pointer (普通对象指针),它用来表示对象的实例信息,看起来像个指针实际上是藏在指针里的对象
二、JVM 系列 - 内存区域
https://www.jianshu.com/p/59f98076b382
三、java对象(准确来说是java实例,非基本类型),不一定都在堆上分配
一般认为java实例的创建,都会在堆上开辟内存创建实例。但是在堆上的哪个区,却是不一定的。比如:最常见是在Eden区分配,如果是Eden区不够(不够会触发一次Monitor GC 还不够)或者大对象(超过JVM配置),会在Old区分配。反正不够怎样,大概率情况会在堆上分配。但是有了JIT技术,一切都不一样啦。
这篇文章分析的很详细:参考文章:求你了,别再说Java对象都是在堆内存上分配空间的了!
四、IO流如果没有被关闭,会不会造成OOM?
首先需要明确,OOM是JVM的行为。只有JVM内存不足,才会报OOM。
我们先思考下IO流占用了哪些资源?如下代码:
private static void readNoClose(int num, String fileName){
try{
InputStream in = new FileInputStream(fileName);
byte[] tempbytes = new byte[1024];
int byteread = in.read(tempbytes);
System.out.println("num=" + num + ",size=" + byteread);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
下面的代码,我们申请1M空间接收文件内容。但是我们把流in仅仅放在方法类。循环调用readNoClose方法。
上面这段代码,在方法执行期间,占用的资源有:
- 对象实例资源,属于JVM所有。
- 打开文件流所需的FD,属于操作系统所有。
如果我们没有关闭流,方法执行完毕后,栈空间释放,in对象,tempbytes对象等等JVM堆里面的所有占用资源,都会被回收,只有占用操作系统的FD没法释放。因为操作系统的资源可不会像JVM那样,会扫描有没有引用。这里的资源,你不显示释放,它就不会释放。到这里,我们发现JVM所持有的所有对象都正确的释放掉了,所以JVM并不会发生OOM。
有人可能会问,不关闭会造成内存泄漏,内存泄漏会造成OOM。谁跟你说泄漏就会造成OOM?这里的泄漏,准确来说不是JVM内存泄漏,而是操作系统所在的内存泄漏。要泄漏也是非JVM管理的内存。JVM压根管不到,何来OOM。
上面代码泄漏的仅仅是FD,而FD占用内存很小。在还没来得及把内存泄漏满,操作系统就会报文件描述符太多,无法再创建。因为同一个文件上,所能打开的FD数量是有限的。
所以上面代码本地运行就会报如下错误。
java.io.FileNotFoundException: /Users/xxx (Too many open files)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
网友评论