学习Java为什么需要理解它的内存机制?

  学习 Java 的理由中,有些是技术性的,有些则是非技术性的。我先描述两个程序的特色(垃圾搜集和例外处理),然后我告诉你:为什么在程序设计的领域中,Java 几乎是必备的技能。我也会告诉你 Java 开发工具的信息和它们吸引人的售价。  感谢老天,有「垃圾收集」真好!  使用 C++,你可能一不小心就写出会当机的程序;如果使用 Java,情况就大不相同了。C++ 程序的头号 bug 是内存配置的失误。C++ 的程序员很辛苦,必须直接配置一块内存,这块内存不用时还必须主动归还。这听起来简单,做起来可不容易,所以 C++ 的程序常常会耗尽内存。  Java 就不同了。虽然你仍需要主动配置内存,但此内存一旦不再使用时就会自动释放,这就称为「垃圾收集(garbage collection)」。垃圾收集机制使得写程序时轻松许多,虽然因此执行时效率稍微变差,但影响可能轻微得你根本感觉不到。  例外处理机制让程序更稳固  不管是什么程序语言,都可以轻易地写出很糟糕的程序,但是使用 Java 想写出很糟糕的程序就不容易了。原因之一是垃圾收集,原因之二是「例外处理机制」。良好的程序员写出来的程序应该在一些意外状况发生时程序依然正常。档案无法开启,怎么办?万一读档读到一半时出问题,怎么办?如果你是用 C++ 或其它语言,你可能会疏于考虑而没进行这些意外状况的处理。你可能会辩白:「我只是在试试看这样写能否行得通,我稍后会回过头来把程序改得更周延」。但结果通常是:程序执行正常后,你又会忙着写新的程序,这么一拖后来就忘了回头处理还不完整的部分。问题终究还是会爆发出来,你终究还是要面对烂摊子。  Java 强迫你在一遇到有可能出问题的地方就要准备好因应之道。Java 的 method 可以丢出例外,用来通知呼叫者程序出状况了,这是相当好的机制。即使你的程序要开启档案,你都必须在程序中写好例外处理方式。  到处都是 Java  到处都可见到 Java,这是一大好处。如果你靠写程序为生,你可能迟早都会接触到 Java。Java 已经渐渐地渗透到各领域,你可以写出 Java servlet,将其挂在 Apache 或其它网页服务器上,你可以写出 Java applet,在网页浏览器上执行。你甚至可以用 Java 写出数据库的 stored procedure,然后安装到 Oracle 8i 上。  我打赌,你身边使用 Java 的同事也会渐渐多起来。1997 年开始,许多大学已经用 Java 取代 C 当作程序设计教学的语言。如此一来,Java 变成了程序员共通的语言。如果学习 Java 所为你带来的唯一好处是方便和同事沟通,那么也值得。  最后,我要提的是:「写一次,到处都可执行」。Java 早期版本(1.0 和 1.1)比较无法完全跨平台,但现在就好多了。如果想散布一个程序到多个平台,又不想改写大部分的程序,那么 Java 是绝佳的选择。Java 2 现在已经可以在 Linux、许多 Unix、和 Windows 上执行了。  MacOS 9 的 Java 仍在 1.1 时代。然而,Apple 的下一代操作系统 OS X 是以 Unix 为核心,这使得移植软件的过程大大简化了。我不知道 Apple 官方的说法为何,但是在今年三月的时候,我就已经看到 OS X developer release 3 上面执行着 Java 2。我很有自信 Java 2 将可以在 Linux、OS X、和 Windows 上执行,这样已经涵盖了大部分的计算机世界。  Java 免费  Sun 提供 Java 相关的工具,让你可以开发与执行 Java 程序。你无须支付授权费,你也不用花钱买 Java 开发工具。当然,Sun 这么做自有他们的如意算盘,Scott McNealy(Sun 的老板)恨不得能征服世界,但是不管怎样,我们的的确确是不用付钱给任何人就可以享受 Java。  而且,Java 的 API 是珍贵的宝藏,让我们可以轻易地写出功能强大的程序。想写网络程序?已经有 API 了!想连接数据库?已经有 API 了!想写 GUI 程序?已经有 API 了!或者是想做数字影像处理、音乐文件处理、字符串剖析、数字签章?通通有 API 了!身为一个程序员,有这么多好用的 API 真的是再高兴不过的事了,这些 Java API 让我们不用「重新发明轮子」,省却不少功夫。Java 有这么广泛、标准、先进的 API,简直是让 C++ 程序员忌妒死了。C++ 程序员常要花时间学一些 C++ 类别库(比方说 MFC),然后到 Linux 上又得归零学另一套(因为 Linux 上没有 MFC)。一旦你学会了某 Java API,到哪儿都一样不会变动,不用重学。  日光浴  Java 比其它语言来得有趣许多。Java 程序语言有许多「防呆装置」让你不会在程序中犯下大错,所以你可以很快地把程序写完,而如果使用其它语言必须要花更多时间。一份有趣的资料显示:用 Java 写程序比用其它语言快了四到十倍。我知道这听起来很不可思议,不过你可以问问周遭懂 Java 的人看看。不用花很多时间找 bug,意味着你可以在海滩上休息更久,意味着你可以接受阳光的日光浴而非「屏幕的日光浴」。用 Java 为你赚进的银两为自己买一副太阳眼镜吧!java学校www.lovochina.com
楼主发言:1次 发图:0张 | 更多
  很赞同楼主  觉得c系列,如果学得不精,真的最好别使用,因为很容易出问题,而且出的问题后果都比较严重  java感觉明显更受市场关注
  说的不错~~
  因为爱~所以爱~
  很多人都所java很丑,我真的无法理解,我是Java程序员,还没体会到别的语言的不足,也没感觉到Java很丑,楼主说的有道理,但也不要过于夸大Java,现在是多语言横行的时代,Java也在慢慢衰落,我很担心。
  zoohoo.cn,我发布的一个小站,顶java,
  内 容 简 介  本书基于Java SE平台,从初学者的角度出发,通过通俗易懂的语言、丰富的实例、细腻的讲解,由浅入深、循序渐进地全面介绍了Java语言的基础知识和常用开发技术。本书讲解时多用类比、对比等写作手法,并配合大量图示和实例,对难点给出了必要提示。书中的所有知识点对应具体的编程实例,并对实例代码给出了详细注释,便于读者一边学习一边动手实践,既可以提高动手能力,也可以激发学习兴趣。另外,本书提供了大量的企业笔试和面试题,便于读者了解行业面试和笔试的特点,从而顺利应聘。  本书21章,分为4篇。第1篇介绍了Java的发展历程、基础语法、流程控制、数组、方法和字符串;第2篇介绍了Java面向对象编程中类和对象的实现。第3篇介绍了Java应用程序设计,涵盖异常处理、I/O、多线程、常用类库、泛型、集合、枚举、反射机制、数据库编程和网络编程等;第4篇实战开发介绍了Java图形界面开发及Eclipse开发工具的使用,最后通过一个项目案例介绍了Java界面开发和数据库设计。  本书配1张DVD光盘,内容为本书配套教学视频及源代码。另外,光盘中还赠送了大量的Java开发范例、模块及项目案例的源代码和教学视频。  本书非常适合作为Java编程初学者的参考书,也适合Java程序员作为案头必备的手册,对于大中专院校的学生,本书也是一本不可多得的详解教程。  
<span class="count" title="万
请遵守言论规则,不得违反国家法律法规回复(Ctrl+Enter)没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
既然 Java 的垃圾回收机制能够自动的回收内存,怎么还会出现内存泄漏的情况呢
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
内存资源是有限的,垃圾回收只回收“垃圾”,对于你的程序运行有用的对象不会被回收。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
内存溢出分两种情况:一种是栈溢出,比如调用了一个无限递归。还有一种是堆溢出,即new 出来的对象没有即使销毁,比如一直new。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
因为有些写的很蠢的程序会在GC机制生效之前无限地创建对象。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
一般来说,Java中的内存泄漏指的是已经不再被程序需要的已分配内存无法被回收。垃圾回收机制通过对象与Root对象的可达性判断内存是否可以被回收,但由于编程错误或其他原因,导致过期的对象引用仍然被持有,垃圾回收器无法回收相关空间。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
占着茅坑不拉屎,他也没办法.推荐看下我同事写的博客:
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
一些对象其实不需要了但却一直被引用,没办法回收
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
就目前来说,人做的东西还不能超越人本身,java的GC算法是人写出来的,奈何就有人会作死写出让GC无法回收的代码来
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
这就如同中国那么大,为什么还有人在朝阳区懵逼一样。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
我自己的理解,说的不对的地方欢迎指正。JDK6中,String的一个方法叫subString,这个是用来生成一个子字符串的。为了更加快速的生成,String有一个构造函数,String(int offset, int count, char value[]) {
this.value =
this.offset =
this.count =
}直接指向了原来String的数组。我们都知道,每次都会生成一个新的常量池中的String字符串。然而这个引用就导致了原来的String无法被回收。因为subString的value会指向他。这里就会导致内存泄露。
JVM的确是自己进行GC的,不用程序员过多干涉,但是由于一些错误操作,导致一些本来不在需要使用的对象仍然有引用,才会导致内存泄露的。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
JVM:程序员抓着垃圾不放,我也很为难啊。
同步到新浪微博
分享到微博?
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。谈谈Java内存管理 - ImportNew
对于一个Java程序员来说,大多数情况下的确是无需对内存的分配、释放做太多考虑,对Jvm也无需有多么深的理解的。但是在写程序的过程中却也往往因为这样而造成了一些不容易察觉到的内存问题,并且在内存问题出现的时候,也不能很快的定位并解决。因此,了解并掌握Java的内存管理是一个合格的Java程序员必需的技能,也只有这样才能写出更好的程序,更好地优化程序的性能。
一. 背景知识
根据网络可以找到的资料以及笔者能够打听到的消息,目前国内外著名的几个大型互联网公司的语言选型概括如下:
Google: C/C++ Go Python Java JavaScript,不得不提的是Google贡献给java社区的guava包质量非常高,非常值得学习和使用。
Youtube、豆瓣: Python
Fackbook、Yahoo、Flickr、新浪:php(优化过的php vm)
网易、阿里、搜狐: Java、PHP、Node.js
Twitter: Ruby-&Java,之所以如此就在于与Jvm相比,Ruby的runtime是非常慢的。并且Ruby的应用比起Java还是比较小众的。不过最近twitter有往scala上迁移的趋势。
可见,虽然最近这些年很多言论都号称java已死或者不久即死,但是Java的语言应用占有率一直居高不下。与高性能的C/C++相比,Java具有gc机制,并且没有那让人望而生畏的指针,上手门槛相对较低;而与上手成本更低的PHP、Ruby等脚本语言来说,又比这些脚本语言有性能上的优势(这里暂时忽略FB自己开发的HHVM)。
对于Java来说,最终是要依靠字节码运行在jvm上的。目前,常见的jvm有以下几种:
Sun HotSpot
BEA Jrockit
Dalvik(Android)
其中以HotSpot应用最广泛。目前sun jdk的最新版本已经到了8,但鉴于新版的jdk使用并未普及,因此本文仅仅针对HotSpot虚拟机的jdk6来讲。
二. Jvm虚拟机内存简介
2.1 Java运行时内存区
Java的运行时内存组成如下图所示:
其中,对于这各个部分有一些是线程私有的,其他则是线程共享的。
线程私有的如下:
程序计数器当前线程所执行的字节码的行号指示器
Java虚拟机栈Java方法执行的内存模型,每个方法被执行时都会创建一个栈帧,存储局部变量表、操作栈、动态链接、方法出口等信息。
每个线程都有自己独立的栈空间
线程栈只存基本类型和对象地址
方法中局部变量在线程空间中
本地方法栈Native方法服务。在HotSpot虚拟机中和Java虚拟机栈合二为一。
线程共享的如下:
Java堆存放对象实例,几乎所有的对象实例以及其属性都在这里分配内存。
方法区存储已经被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等数据。
运行时常量池方法区的一部分。用于存放编译期生成的各种字面量和符号引用。
直接内存NIO、Native函数直接分配的堆外内存。DirectBuffer引用也会使用此部分内存。
2.2 对象访问
Java是面向对象的一种编程语言,那么如何通过引用来访问对象呢?一般有两种方式:
通过句柄访问
此种方式也是HotSpot虚拟机采用的方式。
2.3 内存溢出
在JVM申请内存的过程中,会遇到无法申请到足够内存,从而导致内存溢出的情况。一般有以下几种情况:
虚拟机栈和本地方法栈溢出
StackOverflowError: 线程请求的栈深度大于虚拟机所允许的最大深度(循环递归)
OutOfMemoryError: 虚拟机在扩展栈是无法申请到足够的内存空间,一般可以通过不停地创建线程引起此种情况
Java堆溢出: 当创建大量对象并且对象生命周期都很长的情况下,会引发OutOfMemoryError
运行时常量区溢出:OutOfMemoryError:PermGen space,这里一个典型的例子就是String的intern方法,当大量字符串使用intern时,会触发此内存溢出
方法区溢出:方法区存放Class等元数据信息,如果产生大量的类(使用cglib),那么就会引发此内存溢出,OutOfMemoryError:PermGen space,在使用Hibernate等框架时会容易引起此种情况。
三. 垃圾收集
3.1 理论基础
在通常情况下,我们掌握java的内存管理就是为了应对网站/服务访问慢,慢的原因一般有以下几点:
内存:垃圾收集占用cpu;放入了太多数据,造成内存泄露(java也是有这种问题的^_^)
I/O速度太慢
依赖的其他服务响应太慢
复杂的业务逻辑或者算法造成响应的缓慢
其中,垃圾收集对性能的影响一般有以下几个:
程序吞吐量显著下降
响应时间变慢
垃圾收集的一些基本概念
Concurrent Collector:收集的同时可运行其他的工作进程
Parallel Collector: 使用多CPU进行垃圾收集
Stop-the-word(STW):收集时必须暂停其他所有的工作进程
Sticky-reference-count:对于使用“引用计数”(reference count)算法的GC,如果对象的计数器溢出,则起不到标记某个对象是垃圾的作用了,这种错误称为sticky-reference-count problem,通常可以增加计数器的bit数来减少出现这个问题的几率,但是那样会占用更多空间。一般如果GC算法能迅速清理完对象,也不容易出现这个问题。
Mutator:mutate的中文是变异,在GC中即是指一种JVM程序,专门更新对象的状态的,也就是让对象“变异”成为另一种类型,比如变为垃圾。
On-the-fly:用来描述某个GC的类型:on-the-fly reference count garbage collector。此GC不用标记而是通过引用计数来识别垃圾。
Generational gc:这是一种相对于传统的“标记-清理”技术来说,比较先进的gc,特点是把对象分成不同的generation,即分成几代人,有年轻的,有年老的。这类gc主要是利用计算机程序的一个特点,即“越年轻的对象越容易死亡”,也就是存活的越久的对象越有机会存活下去(姜是老的辣)。
吞吐量与响应时间
牵扯到垃圾收集,还需要搞清楚吞吐量与响应时间的含义
吞吐量是对单位时间内完成的工作量的量度。如:每分钟的 Web 服务器请求数量
响应时间是提交请求和返回该请求的响应之间使用的时间。如:访问Web页面花费的时间
吞吐量与访问时间的关系很复杂,有时可能以响应时间为代价而得到较高的吞吐量,而有时候又要以吞吐量为代价得到较好的响应时间。而在其他情况下,一个单独的更改可能对两者都有提高。通常,平均响应时间越短,系统吞吐量越大;平均响应时间越长,系统吞吐量越小; 但是,系统吞吐量越大, 未必平均响应时间越短;因为在某些情况(例如,不增加任何硬件配置)吞吐量的增大,有时会把平均响应时间作为牺牲,来换取一段时间处理更多的请求。
针对于Java的垃圾回收来说,不同的垃圾回收器会不同程度地影响这两个指标。例如:并行的垃圾收集器,其保证的是吞吐量,会在一定程度上牺牲响应时间。而并发的收集器,则主要保证的是请求的响应时间。
找出堆中活着的对象
释放死对象占用的资源
定期调整活对象的位置
Mark-Sweep 标记-清除
Mark-Sweep-Compact 标记-整理
Copying Collector 复制算法
Mark-标记从”GC roots”开始扫描(这里的roots包括线程栈、静态常量等),给能够沿着roots到达的对象标记为”live”,最终所有能够到达的对象都被标记为”live”,而无法到达的对象则为”dead”。效率和存活对象的数量是线性相关的。
Sweep-清除扫描堆,定位到所有”dead”对象,并清理掉。效率和堆的大小是线性相关的。
Compact-压缩对于对象的清除,会产生一些内存碎片,这时候就需要对这些内存进行压缩、整理。包括:relocate(将存货的对象移动到一起,从而释放出连续的可用内存)、remap(收集所有的对象引用指向新的对象地址)。效率和存活对象的数量是线性相关的。
Copy-复制将内存分为”from”和”to”两个区域,垃圾回收时,将from区域的存活对象整体复制到to区域中。效率和存活对象的数量是线性相关的。
其中,Copy对比Mark-sweep
内存消耗:copy需要两倍的最大live set内存;mark-sweep则只需要一倍。
效率上:copy与live set成线性相关,效率高;mark-sweep则与堆大小线性相关,效率较低。
分代收集是目前比较先进的垃圾回收方案。有以下几个相关理论
分代假设:大部分对象的寿命很短,“朝生夕死”,重点放在对年青代对象的收集,而且年青代通常只占整个空间的一小部分。
把年青代里活的很长的对象移动到老年代。
只有当老年代满了才去收集。
收集效率明显比不分代高。
HotSpot虚拟机的分代收集,分为一个Eden区、两个Survivor去以及Old Generation/Tenured区,其中Eden以及Survivor共同组成New Generatiton/Young space。通常将对New Generation进行的回收称为Minor GC;对Old Generation进行的回收称为Major GC,但由于Major GC除并发GC外均需对整个堆以及Permanent Generation进行扫描和回收,因此又称为Full GC。
Eden区是分配对象的区域。
Survivor是minor/younger gc后存储存活对象的区域。
Tenured区域存储长时间存活的对象。
分代收集中典型的垃圾收集算法组合描述如下:
年青代通常使用Copy算法收集,会stop the world
老年代收集一般采用Mark-sweep-compact, 有可能会stop the world,也可以是concurrent或者部分concurrent。
那么何时进行Minor GC、何时进行Major GC? 一般的过程如下:
对象在Eden Space完成内存分配
当Eden Space满了,再创建对象,会因为申请不到空间,触发Minor GC,进行New(Eden + S0 或 Eden S1) Generation进行垃圾回收
Minor GC时,Eden Space不能被回收的对象被放入到空的Survivor(S0或S1,Eden肯定会被清空),另一个Survivor里不能被GC回收的对象也会被放入这个Survivor,始终保证一个Survivor是空的
在Step3时,如果发现Survivor区满了,则这些对象被copy到old区,或者Survivor并没有满,但是有些对象已经足够Old,也被放入Old Space。
当Old Space被放满之后,进行Full GC
但这个具体还要看JVM是采用的哪种GC方案。
New Generation的GC有以下三种:
ParallelScavenge
对于上述三种GC方案均是在Eden Space分配不下时,触发GC。
Old Generation的GC有以下四种:
Serial Old
对于Serial Old, Parallel Old而言触发机制为
Old Generation空间不足
Permanent Generation空间不足
Minor GC时的悲观策略
Minor GC后在Eden上分配内存仍然失败
执行Heap Dump时
外部调用System.gc,可通过-XX:+DisableExplicitGC来禁止
对于CMS而言触发机制为:
当Old Generation空间使用到一定比率时触发;HopSpot V1.6中默认是92%,可通过PrintCMSInitiationStatistics(此参数在V1.5中不能用)来查看这个值到底是多少;可通过CMSInitiatingOccupancyFaction来强制指定,默认值并不是复制在这个值上,是根据如下公式计算出来的:((100 -MinHeapFreeRatio) +(double)(CMSTriggerRatio* MinHeapFreeRatio) / 100.0)/ 100.0;MinHeapFreeRatio默认值:40 CMSTriggerRatio默认值:80
当Permanent Generation采用CMS收集且空间使用到一定比率触发;Permanent Generation采用CMS收集需设置:-XX:+CMSClassUnloadingEnabled Hotspot V1.6中默认为92%;可通过CMSInitiatingPermOccupancyFraction来强制指定,同样,它是根据如下公式计算出来的:((100 -MinHeapFreeRatio) +(double)(CMSTriggerPermRatio* MinHeapFreeRatio) / 100.0)/ 100.0;MinHeapFreeRatio默认值:40 CMSTriggerPermRatio默认值:80
Hotspot根据成本计算决定是否需要执行CMS GC;可通过-XX:+UseCmsInitiatingOccupancyOnly来去掉这个动态执行的策略。
外部调用System.gc,且设置了ExplicitGCIInvokesC需要注意,在hotspot 6中,在这种情况下如果应用同时使用了NIO,可能会出现bug。
3.2 HotSpot垃圾收集器
上图即为HotSpot虚拟机的垃圾收集器组成。
Serial收集器
-XX:+UserSerialGC参数打开此收集器
Client模式下新生代默认的收集器。
较长的stop the world时间
简单而高效
此收集器的一个工作流程如下如所示:
ParNew收集器
-XX:+UserParNewGC
+UseConcuMarkSweepGC时默认开启
Serial收集器的多线程版本
默认线程数与CPU数目相同
-XX:ParrallelGCThreads指定线程数目
对比Serial收集器如下图所示:
Parallel Scavenge收集器
新生代并行收集器
采用Copy算法
主要关注的是达到可控制的吞吐量,“吞吐量优先”
-XX:MaxGCPauseMillis -XX:GCTimeRAtion两个参数精确控制吞吐量
-XX:UseAdaptiveSizePolicy GC自适应调节策略
Server模式的默认新生代收集器
Serial Old收集器
Serial的老年代版本
Client模式的默认老年代收集器
CMS收集器的后备预案,Concurrent Mode Failure时使用
-XX:+UseSerialGC开启此收集器
Parallel Old收集器
-XX:+UseParallelGC -XX:+UseParallelOldGC启用此收集器
Server模式的默认老年代收集器
Parallel Scavenge的老年代版本,使用多线程和”mark-sweep”算法
关注点在吞吐量以及CPU资源敏感的场合使用
一般使用Parallel Scavenge + Parallel Old可以达到最大吞吐量保证
并发低停顿收集器
-XX:UseConcMarkSweepGC 开启CMS收集器,(默认使用ParNew作为年轻代收集器,SerialOld作为收集失败的垃圾收集器)
以获取最短回收停顿时间为目标的收集器,重视响应速度,希望系统停顿时间最短,会和互联网应用。
四个步骤:
初始标记 Stop the world: 只标记GC roots能直接关联到的对象,速度很快。
并发标记:进行GC roots tracing,与用户线程并发进行
重新标记 Stop the world:修正并发标记期间因程序继续运行导致变动的标记记录
对比serial old收集器如下图所示:
CMS有以下的缺点:
CMS是唯一不进行compact的垃圾收集器,当cms释放了垃圾对象占用的内存后,它不会把活动对象移动到老年代的一端
对CPU资源非常敏感。不会导致线程停顿,但会导致程序变慢,总吞吐量降低。CPU核越多越不明显
无法处理浮动垃圾。可能出现“concurrent Mode Failure”失败, 导致另一次full GC ,可以通过调整-XX:CMSInitiatingOccupancyFraction来控制内存占用达到多少时触发gc
大量空间碎片。这个可以通过设置-XX:UseCMSCompacAtFullCollection(是否在full gc时开启compact)以及-XX:CMSFullGCsBeforeCompaction(在进行compact前full gc的次数)
G1算法在Java6中还是试验性质的,在Java7中正式引入,但还未被广泛运用到生产环境中。它的特点如下:
使用标记-清理算法
不会产生碎片
可预测的停顿时间
化整为零:将整个Java堆划分为多个大小相等的独立区域
-XX:+UseG1GC可以打开此垃圾回收器
-XX:MaxGCPauseMillis=200可以设置最大GC停顿时间,当然JVM并不保证一定能够达到,只是尽力。
3.3 调优经验
需要打开gc日志并读懂gc日志:-XX:PrintHeapAtGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamp -Xloggc:$CATALINA_BASE/logs/gc.log
垃圾回收的最佳状态是只有young gc,也就是避免生命周期很长的对象的存在。
从young gc开始,尽量给年青代大点的内存,避免full gc
注意Survivor大小
注意内存墙:4G~5G
GC日志简介
: [GC [PSYoungGen: 1375104K-&16K)] 4145665K-&82400K), 0.0174410 secs] [Times: user=0.27 sys=0.00, real=0.02 secs]
:发生的时间点,JVM运行的时间长度,以度为单位,也可以格式化成固定的时间格式(使用-XX:+PrintGCDateStamps)
PSYoungGen:发生了何种类型的GC,此处代表发生了年轻代的GC
1375104K:回收前的大小
11376K:回收后的大小
1386176K:YOUNG代的大小
4145665 K:回收前总的占用大小
2782002K:回收后的占用大小
4182400K:总占用大小
0.0174410:垃圾收集停顿时间
0.27和0.00:代表在用户态(user)和系统状(sys)的CPU运行时间
0.02 secs:代表实际的GC的运行时间
注:上面实际GC的运行时间小于用户态和系统态的时间总和,是由于前者仅指CPU的运行时间,包括等待或IO阻塞的时间,而现在的GC是采用多线程收集的,同时机器也是多个CPU,因此,大部分是二者之和要比前面的值大。如果是采用串形化收集器的话,二者时间几乎相差不多。
老年代使用建议
Parallel GC(-XX:+UseParallel[Old]GC)
Parallel GC的minor GC时间是最快的, CMS的young gc要比parallel慢, 因为内存碎片
可以保证最大的吞吐量
确实有必要才改成CMS或G1(for old gen collections)
小对象allocate的代价很小,通常10个CPU指令;收集掉新对象也非常廉价;不用担心活的很短的小对象
大对象分配的代价以及初始化的代价很大;不同大小的大对象可能导致java堆碎片,尤其是CMS, ParallelGC 或 G1还好;尽量避免分配大对象
避免改变数据结构大小,如避免改变数组或array backed collections / containers的大小;对象构建(初始化)时最好显式批量定数组大小;改变大小导致不必要的对象分配,可能导致java堆碎片
对象池可能潜在的问题
增加了活对象的数量,可能增加GC时间
访问(多线程)对象池需要锁,可能带来可扩展性的问题
小心过于频繁的对象池访问
GC的庞氏骗局
虽然GC在大多数情况下还是正常的,但有时候JVM也会发生欺骗你的场景, JVM不停的在垃圾回收,可是每次回收完后堆却还是满的,很明显程序内存被使用完了,已经无法正常工作了,但JVM就是不抛出OutOfMemoryError(OOM)这个异常来告诉程序员内部发出了什么,只是不停的做老好人尝试帮我们做垃圾回收,把服务器的资源耗光了。
出现这种现象的一种典型情况就是GC的GCTimeLimit和GCHeapFreeLimit参数设置不合适。GCTimeLimit的默认值是98%,也就是说如果大于等于98%的时间都用花在GC上,则会抛出OutOfMemoryError。GCHeapFreeLimit是回收后可用堆的大小,默认值是2%,也就是说只要有多余2%的内存可用就认为此次gc是成功的。如果GCTimeLimit设置过大或者GCHeapFreeLimit设置过小那么就会造成GC的庞式骗局,不停地进行垃圾回收。
四. Java7、8带来的一些变化
Java7带来的内存方面的一个很大的改变就是String常量池从Perm区移动到了Heap中。调用String的intern方法时,如果存在堆中的对象,则会直接保存对象的引用,而不会重新创建对象。
Java7正式引入G1垃圾收集器用于替换CMS。
Java8中,取消掉了方法区(永久代),使用“元空间”替代,元空间只与系统内存相关。
Java 8 update 20所引入的一个很棒的优化就是G1回收器中的字符串去重(String deduplication)。由于字符串(包括它们内部的char[]数组)占用了大多数的堆空间,这项新的优化旨在使得G1回收器能识别出堆中那些重复出现的字符串并将它们指向同一个内部的char[]数组,以避免同一个字符串的多份拷贝,那样堆的使用效率会变得很低。可以使用-XX:+UseStringDeduplication这个JVM参数来试一下这个特性。
你说的那个是继承的时候起作用,我试了不管用
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:ImportNew.
广告与商务合作QQ:
&#8211; 好的话题、有启发的回复、值得信赖的圈子
&#8211; 写了文章?看干货?去头条!
&#8211; 为IT单身男女服务的征婚传播平台
&#8211; 优秀的工具资源导航
&#8211; 活跃 &#038; 专业的翻译小组
&#8211; 国内外的精选博客文章
&#8211; UI,网页,交互和用户体验
&#8211; JavaScript, HTML5, CSS
&#8211; 专注Android技术分享
&#8211; 专注iOS技术分享
&#8211; 专注Java技术分享
&#8211; 专注Python技术分享
& 2018 ImportNew}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信