《编程导论(Java)·7.4.3 堆上的对象》

来源:互联网 发布:mac 强制删除文件夹 编辑:程序博客网 时间:2024/06/05 03:43

Java的存储管理模式中,堆分配(heap-based memoryallocation,dynamic memory allocation)是Java程序员需要大致了解的。

7.4.3的学习要点

  • 对象堆上分配的含义;
  • 现代JVM,引用作为直接指针实现(速度和碎片整理)


1.Java对象的内存总是在heap中分配

在Java语言层面,任何Java对象所需的空间都在Java堆上动态分配,遵循堆分配的存储管理模式

涉及两个问题:

Java不在栈中保存对象的数据的好处。对比C++,程序员不需要知道对象的大小(虽然通过某些技术可以获得类似C/C++的sizeof()操作);不需要区分stack中和heap中的对象(C++语言中对象空间的分配,将形成两种对象模型,以及子类的切割问题)。

抽象和实现。不在栈中分配对象空间仅仅是Java语言层面的结论。准确说,仅具有《Java虚拟机规范》中规定的抽象的、逻辑上的含义。Java程序员从来不需要花费时间和精力去考虑能否在栈中分配对象空间。但是,为了提供尽可能好的性能,JVM的实现者则可以使用栈分配模式保存“适当的”对象。例如当它采用逃逸分析(Escape analysis)技术判定一个特定对象的整个生命周期不会超过/逃逸出一个给定的JVM栈帧的生命周期,那么该对象就能够安全地进行栈分配。【补充:这也是修改String 类的substring(int begin,intend)实现的重要原因,修改后的性能损失总得有些好处来补偿。7.4.4 String对象问题】

必须充分认识到抽象和实现分离的意义——JVM的使用者不必关心底层的、与性能相关的细节,而JVM的实现者又能够提供尽可能好的性能。

2.对象的内部表示

“PL6. 面向对象程序设计·Internal representations ofobjects and method tables 对象和方法表的内部表示”的知识单元,在Java语言的教学中远不如C++中那么值得详尽介绍。

要点:

对象所需的空间保存它所有的(包括所有祖先类定义的)实例变量的值,以及系统开销(overhead)。因为通过对象的引用,JVM除了需要定位对象的实例变量的值,还必须能够进行相关的操作。系统开销包括:访问它在方法区中的类型数据,例如在造型为父类时、执行instanceof操作时等。此外,Java对象还需要保存与线程相关的数据——锁,JVM中的每一个线程都有一个锁对象;与垃圾回收相关的数据,随着垃圾回收算法的不同,而被附加不同的数据。

所以,《Java虚拟机规范》中没有规定对象的内部表示。对象的内部表示由JVM实现者决定,它关系着整个堆以及垃圾回收器的设计。

但是,现代JVM的引用都是作为指针实现的。换言之,在JVM看来,引用就是指针;(早期的JVM实现中(如Classic VM),引用指向保存若干指针的结构,称为句柄——相关的内容和图,略)。

在Java程序员看来,引用是安全指针——没有算术操作的功能。


图 7‑7 引用作为直接指针实现

更多的时候,我们画对象的空间时会将系统开销省略掉。而在《编程导论(Java)》中,从[2.4.1 引用的涵义]开始就一直将系统开销画出来。

(图7-7的“类型数据”后面应该加个“等”)

随便提醒:图7-7中,引用变量Xxx@...它的位置可以是方法区(method area)、Java堆和Java栈。



1 0
原创粉丝点击