前面一篇文章介绍了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.尽量在合适的场景下使用对象池技术以提高系统性能

Java虚拟机内存优化实践的更多相关文章

  1. Java虚拟机内存模型和volatile型变量

    Java虚拟机内存模型 了解Java虚拟机的内存模型,有助于我们明白为什么会发生线程安全问题. 上面这幅图是<深入理解Java虚拟机-JVM高级特性与最佳实践>的书中截图. 线程共享的变量 ...

  2. Java虚拟机内存分配详解

    简介 了解Java虚拟机内存分布的好处 1.了解Java内存管理的细节,有助于程序员编写出性能更好的程序.比如,在新的线程创建时,JVM会为每个线程创建一个专属的栈 (stack),其栈是先进后出的数 ...

  3. Java------------JVM(Java虚拟机)优化大全和案例实战

    JVM(Java虚拟机)优化大全和案例实战 堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Ge ...

  4. Java虚拟机内存模型及垃圾回收监控调优

    Java虚拟机内存模型及垃圾回收监控调优 如果你想理解Java垃圾回收如果工作,那么理解JVM的内存模型就显的非常重要.今天我们就来看看JVM内存的各不同部分及如果监控和实现垃圾回收调优. JVM内存 ...

  5. Citrix 服务器虚拟化之十三 Xenserver虚拟机内存优化与性能监控

    Citrix 服务器虚拟化之十三   Xenserver虚拟机内存优化与性能监控 XenServer的DMC通过自动调节运行的虚拟机的内存,每个VM分配给指定的最小和最大内存值之间,以保证性能并允许每 ...

  6. 如何设置Java虚拟机内存以适应大程序的装载

    Java虚拟机对于运行时的程序所占内存是有限制的,当我们的项目或者程序很大时,往往会照成内存溢出. 举个例子: public class SmallTest1 { public static void ...

  7. 打包apk java 虚拟机内存不足

    解决方案:在android->sdk->build-tools-android-version 中有个 dx.bat dx.bat --dex 命令的dx.bat脚本有这样一句代码 REM ...

  8. Java虚拟机-内存tips

    java虚拟机内存可以分为独占区和共享区. 独占区:虚拟内存栈.本地方法栈.程序计数器. 共享区:方法区.Java堆(用来存放对象实例). 程序计数器 比较小的内存空间,当前线程所执行的字节码的行号指 ...

  9. Java虚拟机内存溢出异常--《深入理解Java虚拟机》学习笔记及个人理解(三)

    Java虚拟机内存溢出异常--<深入理解Java虚拟机>学习笔记及个人理解(三) 书上P39 1. 堆内存溢出 不断地创建对象, 而且保证创建的这些对象不会被回收即可(让GC Root可达 ...

随机推荐

  1. C文件读写函数介绍(转)

    1.fopen() fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能:为使用而打开一个流,把一个文件和此 ...

  2. HashSet内存泄露

    import java.util.HashSet; import java.util.Set; public class PersonTest { public static void main(St ...

  3. 【网络流#9】POJ 2135 Farm Tour 最小费用流 - 《挑战程序设计竞赛》例题

    [题意]给出一张无向图,从1开始到n,求两条没有公共边的最短路,使得路程总和最小 每条边的权值设为费用,最大流量设为1,然后就是从源点到汇点流量为2的最小费用流. 因为是规定了流量,新建一个源点和一个 ...

  4. 轮播图--JS手写

    轮播图基本每个网站都会有,也有很多的JQuery插件可以用,这里是用JS代码写的. @{ Layout = null; } <!DOCTYPE html> <html> < ...

  5. mui实现支付宝支付功能

    <!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>H ...

  6. python单元测试之unittest

    unittest是python标准库,从2.1开始就有. 标准的使用流程: 1:实现一个unittest.TestCase的子类 2:在其中定义以_test开头的实例函数 3:用unittest.ma ...

  7. ajax提交请求为啥url要用这个函数encodeURI

    参考如下: 如果你是通过form提交的,那就不需要用这个了.但是如果是你使用url的方式例如:ajax提交到后台的,就需要对url进行encodeURI编码,否则,会导致后台出现各种乱码,不加enco ...

  8. 网页上facebook分享功能的具体实现

    1,一个链接: 参数是要分享的页面的链接 代码如下: <a style="width:35px; height:40px; position:relative; top:10px; l ...

  9. 数据库的事务处理必须满足ACID原则,ACID分别是指什么

    http://blog.csdn.net/dingxingmei/article/details/39270375

  10. Centos 5.2安装配置DNS服务器

    BIND安装配置(主从)我的系统环境:centos 5.2 作者:哈密瓜 主:我采用的是yum安装[root@linux src]#yum -y install bind* 生成rndc控制命令的ke ...