垃圾收集与Java性能优化探讨.pdfVIP

  • 0
  • 0
  • 约4.93千字
  • 约 4页
  • 2026-02-10 发布于北京
  • 举报

附录E关于收集的一些话

“很难相信Java居然能和C++一样快,甚至还能更快一些。”

据的实践,这种确实成立。然而,我也发现许多关于速度的怀疑都来

自一些早期的实现方式。由于这些方式并非特别有效,所以没有一个模型可供参

考,不能解释Java速度快的。

我之所以想到速度,部分是由于C++模型。C++将自己的主要精力放在编译

期间“静态”发生的所有事情上,所以程序的运行期版本非常短小和快速。C++

也直接建立在C模型的基础上(主要为了向后兼容),但有时仅仅由于它在C中

能按特定的方式工作,所以也是C++中最方便的法。最重要的一种情况是

C和C++对内存的管理方式,它是某些人觉得Java速度肯定慢的重要依据:在

Java中,所有对象都必须在内存“堆”里创建。

而在C++中,对象是在堆栈中创建的。这样可达到更快的速度,因为当我们进入

一个特定的作用域时,堆栈指针会向下移动一个单位,为那个作用域内创建的、

以堆栈为基础的所有对象分配空间。而当我们离开作用域的时候(调用完毕

所有局部构建器后),堆栈指针会向上移动一个单位。然而,在C++里创建“内

存堆”(Heap)对象通常会慢得多,因为它建立在C的内存堆基础上。这种内存

堆实际是一个大的内存池,要求必须进行再循环(再生)。在C++里调用delete

以后,释放的内存会在堆里留下一个洞,所以再调用new的时候,分配机

制必须进行某种形式的搜索,使对象的与堆内任何现成的洞相配,否则就会

很快用光堆的空间。之所以内存堆的分配会在C++里对性能造成如此重大的

性能影响,对可用内存的搜索正是一个重要的。所以创建基于堆栈的对象要

快得多。

同样地,由于C++如此多的工作都在编译期间进行,所以必须考虑这方面的因素。

但在Java的某些地方,事情的发生却要显得“动态”得多,它会改变模型。创

建对象的时候,收集器的使用对于提高对象创建的速度产生了显著的影响。

从表面上看,这种似乎有些奇怪——空间的释放会对空间的分配造

成影响,但它正是JVM采取的重要之一,这意味着在Java中为堆对象分配

空间几乎能达到与C++中在堆栈里创建空间一样快的速度。

可将C++的堆(以及更慢的Java堆)想象成一个庭院,每个对象都拥有自己的

一块地皮。在以后的某个时间,这种“”会被抛弃,而且必须再生。但在

某些JVM里,Java堆的工作方式却是颇有不同的。它更象一条传送带:每次分

配了一个新对象后,都会朝前移动。这意味着对象空间的分配可以达到非常

快的速度。“堆指针”简单地向前移至地,所以它与C++的堆栈分配方式几

乎是完全相同的(当然,在数据记录上会多花一些开销,但要比搜索空间快

多了)。

现在,大家可能注意到了堆并非一条传送带。如按那种方式对待它,最终就

要求进行大量的页交换(这对性能的发挥会产生巨大干扰),这样终究会用光内

存,出现内存分页错误。所以这儿必须采取一个技巧,那就是著名的“收集

器”。它在收集“”的同时,也负责压缩堆里的所有对象,将“堆指针”移

至尽可能靠近传送带开头的地方,远离发生(内存)分页错误的地点。收集

器会重新安排所有东西,使其成为一个高速、无限自由的堆模型,同时游刃有余

地分配空间。

为真正掌握它的工作原理,我们首先需要理解不同收集器(GC)采取的工

作方案。一种简单、但速度较慢的GC技术是计数。这意味着每个对象都包

含了一个计数器。每当一个句柄同一个对象连接起来时,计数器就会增

值。每当一个句柄超出自己的作用域,或者设为null时,计数就会减值。这

样一来,只要程序处于运行状态,就需要连续进行计数管理——尽管这种管

理本身的开销比较少。收集器会在整个对象列表中移动巡视,一旦它发现其

中一个计数成为0,就释放它占据的空间。但这样做也有一个缺点:若

对象相互之间进行循环,那么即使计数不是0,仍有可能属于应收掉的

“”。为了找出这种自

您可能关注的文档

文档评论(0)

1亿VIP精品文档

相关文档