java

位置:IT落伍者 >> java >> 浏览文章

深入Java虚拟机之内存优化


发布日期:2022年04月26日
 
深入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=

Minimum percentage of heap free after GC to avoid expansion

◆ XX:MaxHeapFreeRatio=

Maximum percentage of heap free after GC to avoid shrinking

◆ XX:NewRatio=

Ratio of new/old generation sizes [Sparc client:; x server:; x client:]client:+) x:]

◆ XX:NewSize=m

Default size of new generation (in bytes) [ and newer: bit VMs are scaled % larger; x:m; x and older: k]

◆ XX:MaxNewSize=

Maximum size of new generation (in bytes) Since MaxNewSize is computed as a function of NewRatio

◆ XX:SurvivorRatio=

Ratio of eden/survivor space size [Solaris amd: ; Sparc in : ; other Solaris platforms in and earlier: ]

◆ XX:PermSize=

Initial size of permanent generation

◆ XX:MaxPermSize=m

Size of the Permanent Generation [ and newer: bit VMs are scaled % larger; amd: m; client: m]

下面所说通过优化程序算法来提高内存利用率并降低内存风险完全是经验之谈仅供参考如有不妥请指正谢谢!

尽早释放无用对象的引用(XX = null;)

看一段代码

public List<PageData> parse(HtmlPage page) {

List<PageData> list = null;

try {

List valueList = pagegetByXPath(configgetContentXpath())

if (valueList == null || valueListisEmpty()) {

return list;

}

//需要时才创建对象节省内存提高效率

list = new ArrayList<PageData>()

PageData pageData = new PageData()

StringBuilder value = new StringBuilder()

for (int i = ; i < valueListsize() i++) {

HtmlElement content = (HtmlElement) valueListget(i)

DomNodeList<HtmlElement> imgs = contentgetElementsByTagName(img

if (imgs != null && !imgsisEmpty()) {

for (HtmlElement img : imgs) {

try {

HtmlImage image = (HtmlImage) img;

String path = imagegetSrcAttribute()

String format = pathsubstring(pathlastIndexOf( pathlength())

String localPath = D:/images/ + MDHelpermd(path)replace(\\ replace(/ ) + format;

File localFile = new File(localPath)

if (!localFileexists()) {

localFilecreateNewFile()

imagesaveAs(localFile)

}

imagesetAttribute(src file:/// + localPath)

localFile = null;

image = null;

img = null;

} catch (Exception e) {

}

}

//这个对象以后不会在使用了清除对其的引用等同于提前告知GC该对象可以回收了

imgs = null;

}

String text = contentasXml()

valueappend(text)append(<br/>

valueList=null;

content = null;

text = null;

}

pageDatasetContent(valuetoString())

pageDatasetCharset(pagegetPageEncoding())

listadd(pageData)

//这里 pageData=null; 是没用的因为list仍然持有该对象的引用GC不会回收它

value=null;

//这里可不能 list=null; 因为list是方法的返回值否则你从该方法中得到的返回值永远为空而且这种错误不易被发现排除

} catch (Exception e) {

}

return list;

}

谨慎使用集合数据类型如数组链表等数据结构这些数据结构对GC来说回收更复杂

避免显式申请数组空间不得不显式申请时尽量准确估计其合理值

尽量避免在类的默认构造器中创建初始化大量的对象防止在调用其自类的构造器时造成不必要的内存资源浪费

尽量避免强制系统做垃圾内存的回收增长系统做垃圾回收的最终时间

尽量做远程方法调用类应用开发时使用瞬间值变量除非远程调用端需要获取该瞬间值变量的值

尽量在合适的场景下使用对象池技术以提高系统性能               

上一篇:为什么java世界没有真正的快速开发平台

下一篇:java正则匹配解析出时间