只有理解底层的细节,才能更好的理解程序和代码,因此在研究Java代码和算法之前我们先研究一下Java的内存模型。
本文参考周志明的《深入理解Java虚拟机·第二版》,这是一本Java开发人员进阶的必备书籍。
一:为什么需要理解Java虚拟机内存模型
在c和c++的开发中,程序员对内存操作拥有绝对的控制权,需要自己手动为生成的对象设置生命周期以避免内存泄漏和内存溢出问题。而Java在虚拟机的管理下,开发人员不需要关心对象的生命周期,这一切都由虚拟机来进行管理和维护,但是,一旦出现了内存问题,我们排查问题的过程中,便需要理解jvm的内存模型。
二:内存泄漏和内存溢出
内存溢出:out of memory 请求的内存系统无法提供就是内存溢出。
内存泄漏:memory leak 程序无法释放已经申请过的内存就是内存泄漏,内存泄漏导致可用内存越来越少,最终会诱发内存溢出
以发生的方式来看,内存泄漏分为四类:
常发性内存泄漏:发生内存泄漏的代码被多次执行,每次执行导致一次内存泄漏。
偶发性内存泄漏:在某些特定条件下才会执行的内存泄漏代码,常发和偶发是相对的,不同的环境两者可以互换。
一次性内存泄漏:发生内存泄漏的代码只能被执行一次。
隐式内存泄漏:程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到
三:运行时数据内存:
Java虚拟机会把运行时内存分为几个不同的数据区域,它们有各自不同的用途以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域随着用户进程的启动而存在。
注意这里的数据区域分为两类:一种是所有线程共享的,一种是每个线程单独拥有的数据区。
程序计数器:一块较小的内存,它可以看做是当前线程执行的字节码的行号指示器,每个线程拥有自己的程序计数器。
Java虚拟机栈:线程私有,描述的是java方法执行的内存模型,线程请求的栈深度大于虚拟机允许的深度,抛出StackOverflowError。
本地方法栈:
Java堆:存储对象和数组
方法区:运行时常量池是方法区的一部分。
对Java虚拟机内存的基本介绍就是这些,具体内容可以参考本文推荐的书籍。
我也会在后续的博客中针对《深入理解Java虚拟机·第二版》的细节进行分析和总结,欢迎关注。