JVM那些事儿之内存空间管理(三)
来源:互联网 发布:mac口红火鹤鸟 编辑:程序博客网 时间:2024/05/29 21:29
JVM那些事儿之内存空间管理(三)
我们前面说过,JVM是个虚拟机,它没有硬件意义上的内存管理器,所以必须自己虚拟一个内存管理器。这篇文章带大家去了解一下JVM的内存空间管理。
在操作系统中,每次启动一个Java应用时,就会先启动一个JVM进程,Java应用就以一个线程的存在形式运行在这个进程中。JVM会按照应用配置的-VM参数设置需要申请的内存空间和最大内存空间。并且把这个内存按照不同功能区划分出来,方便Java应用模拟使用。
为了节省系统资源,JVM支持同时运行多个Java应用,也就是说,打开新的Java应用时,将它挂载到已经存在的JVM进程中,多个应用共享一个JVM。此时,JVM申请的系统资源就分为:自身需要的内存区、应用间共享的内存区、应用1的内存区、应用2的内存区……
在Java程序运行过程中,JVM定义了各种区域用于存储运行时数据。其中的有些数据区域在JVM启动时创建,并只在JVM退出时销毁。其它的数据区域与每个线程相关。比如说以下这些数据区域,在线程创建时创建,在线程退出时销毁。
程序计数器寄存器(The pc Register)
JVM支持多个线程同时运行。每个JVM都有自己的程序计数器。在任何一个点,每个JVM线程执行单个方法的代码,这个方法是线程的当前方法。如果方法不是native的,程序计数器寄存器包含了当前执行的JVM指令的地址,如果方法是 native的,程序计数器寄存器的值不会被定义。 JVM的程序计数器寄存器的宽度足够保证可以持有一个返回地址或者native的指针。
所有指令都预先存放在内存中,所谓的程序计数器存放的就是现在指令运行到哪了。知道就存着,不知道就空着。注意不要以为它存放的是程序运行了多少行。
栈
1)栈与线程
JVM是基于栈的虚拟机。JVM为每个新创建的线程都分配一个栈。也就是说,对于一个Java程序来说,它的运行就是通过对栈的操作来完成的。栈以栈帧为单位保存线程的状态,换句话说,就是栈里面存了一堆栈帧。
前面我们已经讲过,JVM在执行Java应用的时候,是以方法为单位的,从main方法开始,从上到下依次执行,每当遇到一个方法的时候,程序会创建一个栈帧,并把相应的局部变量表、操作数栈、常量池指针、返回地址存放在这个栈帧中,然后把这个栈帧做压栈操作,即可开始执行该方法内的程序了,在此方法执行期间,这个栈帧将用来保存参数、局部变量、中间计算过程和其他数据等。执行完毕后,再将栈帧做出栈操作,继续执行下面的代码,依次类推,直到程序执行完毕为止。
综上所述,我们大概能知道:
1、栈是先进后出的
2、栈的内存是有上限的,所以方法嵌套调用不能太多层
2)栈中的方法调用
当嵌套方法调用时,嵌套越深,stack的内存就越晚才能释放,因此,在实际开发过程中,不推荐大家使用递归来进行方法的调用,递归很容易导致stack flow。
堆
每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程共享。
跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。
所以,我们发现,Java是面向对象的语言,Java中的所有对象都是存放在堆中的,在栈里只存放一个引用(链接地址)而已。
方法区
基本上都放在堆中实现,保存的是当前装载的类的一些信息。
进阶
线程间的内存共享
对于堆和方法区来说,线程之间的内存理论上来说是共享的,但是在具体编写JVM的厂家来说,大多数都没有实现共享,不共享其实更加容易管理。会有一种堆外内存的说法,这也就是导致堆外内存溢出的元凶。
堆和栈的区别
- 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方 。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
- 栈的优势是,存取速度比堆要快 ,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
- 堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
- JVM那些事儿之内存空间管理(三)
- JVM那些事儿之简介(一)
- JVM那些事儿之执行原理(二)
- JVM内存空间管理
- 敏捷那些事儿(三)
- Ext2那些事儿(三)
- Android 开发之 Gradle那些事儿(三)
- JVM内存那些事儿
- C语言的那些事儿之三
- iOS 越狱开发那些事儿之三
- Linux那些事儿之我是UHCI(27)实战电源管理(三)
- jvm内存管理 1 内存空间
- JVM那些事儿(一)——jvm内存介绍
- 读书笔记JVM探秘之六:编译器的那些事儿
- 测试管理那些事儿
- 项目管理那些事儿
- 项目管理那些事儿
- 管理那些事儿
- Linux下man手册的用法
- 修改MySql最大Sql文件导入大小
- 史上最易懂——ReactNative分组列表SectionList使用详情及示例详解
- Android WebView的使用 js、java代码调用出错chromium(5437)
- Spring中的Bean获取与实例化
- JVM那些事儿之内存空间管理(三)
- uint8_t / uint16_t / uint32_t /uint64_t
- 剑指offer:圆圈中最后剩下的数字
- HDU
- could not bind to address 0.0.0.0:80问题解决
- 有趣--等额本息还款
- 200
- HDOJ1051 Wooden Sticks(贪心)
- 201