《深入理解JVM》(周志明著)<1>

Java虚拟机运行时的数据区,以下所讲的和计算机内存有区别,读者请勿混淆。

  • 程序计数器

Program Counter Register,对于Java内存来说这是占空间很小的一部分。它的作用也很单一,但是必不可少。一般而言,将这部分从概念上来说是这么一个设计的实现理念:字节码解释器工作的时候,计数器改变自己的值,来指示字节码指令运行的行数。由此,可以将计数器理解为当前字节码运行的行号指示器。一般的虚拟机都是如此设计。在程序设计中,有循环、分支、判断语句,它们都是需要程序计数器来指示执行的行号。对于进程的实现,通常采用轮流切换和分配处理器的使用时间来实现。在同一个时间里面,一个内核(CPU)只能执行一个线程,在一个线程完成之后,需要恢复到正确的位置,因此, 在程序计数器中的线程是独立的,不会收到其他线程的影响。对于Java方法,程序计数器会进行记录,但是Native方法,是一个非Java代码实现的方法,不会被程序记录器记录行号。关于Native方法,可以参考native方法在java中介绍及使用图解

  • Java虚拟机栈

Java Virtual Machine Stacks,Java方法里面会定义变量、操作数、方法的出入口等信息。这些信息都将保存在Java虚拟机栈的栈帧中,也就是说一个线程的生命周期和栈的生命周期是一样的,随栈而生,随栈而亡。对于栈而言,存放的局部变量表是县城私有的,因为是局部!具体而言,这边的变量是指局部变量表,它包括基本的数据类型和对象的引用类型(可以是指向对象的引用指针、句柄、指向字解码地址的指令)。局部变量的空间(Slot)在编译期间(启动之前)就会完成大小的分配,也就是这个方法的空间会被分配,具体的变量的大小视情况而定。在虚拟机栈中,涉及到栈的深度(高度),讲一个栈看成是一个木桶,当存放的东西(栈帧)越大时,桶的剩余高度(深度)越小。如果是线程的请求的栈的深度越大,那么可以拥有的存放的栈帧越小,越容易出现栈溢出(Stack Overflow)。在Java中可以通过设置-XSS参数来进行对于栈内存的大小分配。具体的操作过程可以参考JVM调优总结 -Xms -Xmx -Xmn -Xss。还有一种情况,在使用JDBC时,我们进行创建驱动类常会用java.lang.class类中的forName()方法实现,这时,JVM采用动态扩展来进行分配内存,如果动态分配的过程中虚拟机空间不足,会导致内存溢出(OutOfMemory)。实现Java Web的工程中,浏览器跨域调用applet里面的class文件也是属于动态扩展。另这边,我比较特意做了功课,对于两种不一样的Error问题,分别是在单线程和多线程下的不同描述。

  • 本地方法栈 

Native Method Stack,实现的作用和虚拟机栈相同,但是底层的方法是使用非Java写的。在虚拟机中对于这样的方法栈中的语言和数据结构没有规范。关于Native方法,可以参考native方法在java中介绍及使用图解

  • Java堆

Java Heap, 存放是对象的实例。几乎所有的对象实例都放在堆中。随着JIT(即时)编译器的发展,在Java中,产生栈上分配和标量替换技术,使得在堆中的空间更加有效地使用。垃圾收集器主要管理堆,这边具体不说具体的垃圾回收器。在Java堆的区域,可以划分为新生代和老年代。更细可以分From Survivor和To Survivior等。在Java中还有多线程私有的分配缓冲区(Thread Local Allocation Buffer)。在堆中,存储的区域是一个逻辑上连续的空间,因此在物理地址上不要个要求是连续的。在具体的空间设置中,这个也可以是进行设计的,通过-Xmx和-Xms。在堆中,线程是共享的,但是还是要注意,线程必须有自己的寄存器和栈。关于共享可以参考jvm中堆栈的数据共享和线程共享

  • 方法区 

Method Area,这个区域和Java堆功能相近,存储的内容不相同。这里主要掌握运行时常量池(Runtime Constant Pool)即可。方法区中,有编译期间生成的字面量和符号引用,还有运行时常量池 。运行时常量池有动态特性,之所以这么说,由于Java中,运行期间的新的常量也可以放在池中,常常使用的有String类的intern()方法。字符串常量的变化和迭代,可以参考 Java 8: 从永久代(PermGen)到元空间(Metaspace)String中intern方法的作用

  • 直接内存

Direct Memory,这部分在JDK1.4中引入NIO(新输入/输出类),一种基于通道(Channel)和缓冲区(Buffer)的I/O方式,可以使用Native函数库直接分配堆外内存,再通过一个存储在Java堆中的DirectByteBuffer对象作为引用进行操作。这样的好处是,可以减少在Java堆和Native堆中的来回复制。具体的实现操作可以参考JVM直接内存。 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值