Java虚拟机内存优化实践
前面一篇文章介绍了Java虚拟机的体系结构和内存模型,既然提到内存,就不得不说到内存泄露。众所周知,Java是从C++的基础上发展而来的,而C++程序的很大的一个问题就是内存泄露难以解决,尽管Java的JVM有一套自己的垃圾回收机制来回收内存,在许多情况下并不需要java程序开发人员操太多的心,但也是存在泄露问题的,只是比C++小一点。比如说,程序中存在被引用但无用的对象:程序引用了该对象,但后续不会或者不能再使用它,那么它占用的内存空间就浪费了。
我们先来看看GC是如何工作的:监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,当该对象不再被引用时,释放对象(GC本文的重点,不做过多阐述)。很多Java程序员过分依赖GC,但问题的关键是无论JVM的垃圾回收机制做得多好,内存总归是有限的资源,因此就算GC会为我们完成了大部分的垃圾回收,但适当地注意编码过程中的内存优化还是很必要的。这样可以有效的减少GC次数,同时提升内存利用率,最大限度地提高程序的效率。
总体而言,Java虚拟机的内存优化应从两方面着手:Java虚拟机和Java应用程序。前者指根据应用程序的设计通过虚拟机参数控制虚拟机逻辑内存分区的大小以使虚拟机的内存与程序对内存的需求相得益彰;后者指优化程序算法,降低GC负担,提高GC回收成功率。
通过参数优化虚拟机内存的参数如下所示:
Xms
初始Heap大小
Xmx
java heap最大值
Xmn
young generation的heap大小
Xss
每个线程的Stack大小
上面是三个比较常用的参数,还有一些:
XX:MinHeapFreeRatio=40
Minimum percentage of heap free after GC to avoid expansion.
XX:MaxHeapFreeRatio=70
Maximum percentage of heap free after GC to avoid shrinking.
XX:NewRatio=2
Ratio of new/old generation sizes. [Sparc -client:8; x86 -server:8; x86 -client:12.]-client:8 (1.3.1+), x86:12]
XX:NewSize=2.125m
Default size of new generation (in bytes) [5.0 and newer: 64 bit VMs are scaled 30% larger; x86:1m; x86, 5.0 and older: 640k]
XX:MaxNewSize=
Maximum size of new generation (in bytes). Since 1.4, MaxNewSize is computed as a function of NewRatio.
XX:SurvivorRatio=25
Ratio of eden/survivor space size [Solaris amd64: 6; Sparc in 1.3.1: 25; other Solaris platforms in 5.0 and earlier: 32]
XX:PermSize=
Initial size of permanent generation
XX:MaxPermSize=64m
Size of the Permanent Generation. [5.0 and newer: 64 bit VMs are scaled 30% larger; 1.4 amd64: 96m; 1.3.1 -client: 32m.]
下面所说通过优化程序算法来提高内存利用率,并降低内存风险,完全是经验之谈,仅供参考,如有不妥,请指正,谢谢!
1.尽早释放无用对象的引用(XX = null;)
看一段代码:
public List<PageData> parse(HtmlPage page) {
List<PageData> list = null;
try {
List valueList = page.getByXPath(config.getContentXpath());
if (valueList == null || valueList.isEmpty()) {
return list;
}
//需要时才创建对象,节省内存,提高效率
list = new ArrayList<PageData>();
PageData pageData = new PageData();
StringBuilder value = new StringBuilder();
for (int i = 0; i < valueList.size(); i++) {
HtmlElement content = (HtmlElement) valueList.get(i);
DomNodeList<HtmlElement> imgs = content.getElementsByTagName("img");
if (imgs != null && !imgs.isEmpty()) {
for (HtmlElement img : imgs) {
try {
HtmlImage image = (HtmlImage) img;
String path = image.getSrcAttribute();
String format = path.substring(path.lastIndexOf("."), path.length());
String localPath = "D:/images/" + MD5Helper.md5(path).replace("\\", ",").replace("/", ",") + format;
File localFile = new File(localPath);
if (!localFile.exists()) {
localFile.createNewFile();
image.saveAs(localFile);
}
image.setAttribute("src", "file:///" + localPath);
localFile = null;
image = null;
img = null;
} catch (Exception e) {
}
}
//这个对象以后不会在使用了,清除对其的引用,等同于提前告知GC,该对象可以回收了
imgs = null;
}
String text = content.asXml();
value.append(text).append("<br/>");
valueList=null;
content = null;
text = null;
}
pageData.setContent(value.toString());
pageData.setCharset(page.getPageEncoding());
list.add(pageData);
//这里 pageData=null; 是没用的,因为list仍然持有该对象的引用,GC不会回收它
value=null;
//这里可不能 list=null; 因为list是方法的返回值,否则你从该方法中得到的返回值永远为空,而且这种错误不易被发现、排除
} catch (Exception e) {
}
return list;
}
2.谨慎使用集合数据类型,如数组,树,图,链表等数据结构,这些数据结构对GC来说回收更复杂。
3.避免显式申请数组空间,不得不显式申请时,尽量准确估计其合理值。
4.尽量避免在类的默认构造器中创建、初始化大量的对象,防止在调用其自类的构造器时造成不必要的内存资源浪费
5.尽量避免强制系统做垃圾内存的回收,增长系统做垃圾回收的最终时间
6.尽量做远程方法调用类应用开发时使用瞬间值变量,除非远程调用端需要获取该瞬间值变量的值。
7.尽量在合适的场景下使用对象池技术以提高系统性能
推荐阅读
-
4个理由告诉你Java为何排行第一
本文由码农网 –单劼原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!Java已经有20年的历史了,甚...
-
写给精明Java开发者的测试技巧
我们都会为我们的代码编写测试,不是吗?毫无疑问,我知道这个问题的答案可能会从“当然,但你知道怎样才能避免写测试吗?”到“必须...
-
Java 微服务框架 Redkale 入门介绍
Redkale功能Redkale虽然只有1.xM大小,但是麻雀虽小五脏俱全。既可作为服务器使用,也可当工具包使用。作为独立的工...
-
Java内存管理原理及内存区域详解
一、概述Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁...
-
2015年Java开发岗位面试题归类
下面是我自己收集整理的Java岗位今天面经遇到的面试题,可以用它来好好准备面试。一、Java基础1.String...
-
Java 虚拟机类加载机制和字节码执行引擎
引言我们知道java代码编译后生成的是字节码,那虚拟机是如何加载这些class字节码文件的呢?加载之后又是如何进行方法调用的呢?...
-
Java常量池理解与总结
一.相关概念什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态...
-
Java 实现线程死锁
概述春节的时候去面试了一家公司,笔试题里面有一道是使用简单的代码实现线程的‘死锁’,当时没有想到这道题考的是Sync...
-
Java:过去、未来的互联网编程之王
Java对你而言是什么?一门你大学里学过的语言?一个IT行业的通用语言?你相信Java已经为下一次互联网爆炸做好了准备么?Java...
-
20个高级Java面试题汇总
本文由码农网 –小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!这是一个高级Java面试系列题中...
