java内存优化牛刀小试

  小猿做了两年的c++,上个月竟然被调到java项目,于是第一篇随笔就想八一八java的内存优化。

  首先优化这种事,肯定是应该放到最后去做的,不过在写代码的过程中养成良好的习惯也是很重要的。在这里先推荐一本书《编写高质量代码:改善Java程序的151个建议.秦小波》。

  首先,在写代码的时候,尽量少用对象,能用基本变量代替的就用基本变量,这点下面会举例。

  其次,很多时候你想做一个功能,写一段代码,不是用时间换空间就是用空间换时间。要根据这个功能到底是看中时间,还是看中空间,常访问到的必然是要放到内存里的,但是是不是可以进行压缩这个也要看对效率是否有影响。

  其他的就不多说,相信各位都有自己的好习惯。

  主要想说说内存优化。

  小猿现在做的项目需要解析大量数据保存起来,所以如何节省内存非常重要,不然导入一个100M的文件,就占用1G的内存,客户简直要疯掉了。

  于是小猿进行第一步,排查内存的占用情况。

  首先先使用的工具是jdk自带的,jconsole.exe。

  用这个软件可以清晰的看到你程序内存、CPU、线程的情况。

  刚开始小猿发现明明自己程序堆使用内存量没有那么大啊,怎么全部加起来和任务管理器的不一致!再细观察之,程序的eden space占用量很小。原来是没有设置eden space的参数,这个要到启动配置文件去设置:-Xmn,-XX:NewSize,-XX:MaxNewSize,-XX:NewRatio这些项都可以根据自己的需要去设置。

  因为如果没有强制变量直接申请在old gen,变量是先申请在eden gen的,然后经过gc之后,如果这个变量幸存下来,就进入survivor区,然后再经过几次gc,变量就存在old gen区了。

  事实上程序启动稳定之后,可能大部分变量都已经到了old gen区去了,如果你的eden区内存分配过大,总量减去survivor减去eden之后剩下的old区就会不够用了,这个时候虚拟机干什么呢,虚拟机会自动根据你设置的-Xms和-Xmx去扩容,于是你其实虚拟机获得的系统内存里有很多是空闲内存,造成任务管理器里看到的内存比你实际使用的大得多。

  于是小猿第一步调好了启动参数,内存果珍降了一些,但其实这是假象,虚拟机里实际占用的内存还是没有变。

  小猿想知道更详细的内存使用,这就需要MemoryAnalyzer这个工具了,但是使用这个工具前,得生成程序的dump文件,天哪我竟然百度出来的方法有利用增加启动参数+HeapDumpOnOutOfMemoryError并且手动增加异常OutOfMemory来生成dump文件。

  好吧小猿异常出来了,机子down掉了,好心塞。

  终于找到了好的方法,其实jdk自带的jconsole就可以生成的。

  在MBean->com.sun.management->HotSpotDiagnostic->操作->dumpHeap,把p0的值改成你生成dump文件的路径,点dumpHeap就可以。不过dump文件的后缀可不是dump!!!是hprof!!!

  生成之后,用MemoryAnalyzer打开,leak Suspects之后,将会看到一个神奇的饼图。里面显示的就是当前哪些instance占用多少内存,有个details,点之。

  话说打不开MemoryAnalyze的孩纸你们jdk安了么,java环境变量都配好了么。

  看到详细的内存占用信息,有多少个object等等。

  小猿这下终于发现可以优化的地方了。

  之前就对java的String心存怨念,这下怨念更深了,就是之前的那句,能用基本类型就用基本类型。

  小猿发现,有100000个String的object,还有100000个char[]的object。

  好吧,你用String存一个字符串,其实是用他里边的char存字符串,然后他自己还自带了各种亲戚。

  你存一个“0”,String给你的对象大小可是比1Byte大得多!

  所以你可以调String的toCharArray()方法转成char[]保存。

  这里再八一八什么时候用String,什么时候用StringBuffer,什么时候用char。

  其实定义一个常用的常量字符串用String那是极好的。

  比如

  String strTemp = “01”;

  String strTemp2 = “01”;

  这样定义的话,strTemp和strTemp2实际上是共用了一个对象,只不过这个对象的引用是2!

  所以这样定义10000000000个也只是占了一个String对象,这是String特有的常量池。

  那为什么还要用StringBuffer和StringBuild呢?

  因为StringBuffer和StringBuild的append比String的+要好!

  而且String本身设计的时候就是按常量去设计的,而StringBuffer和StringBuild才是真正可改变的字符串。

  但是如果程序要保存大量的没有规则的字符串,这个时候就建议转成char来存。

  这只是字符串类型,其他的int等也是这样的原则,尽量用基本变量保存。

  纵观高大上的java,宣称没有内存泄露的java,如果我们使用不当,是会造成内存浪费的。

  虽然退出程序的那一刻内存都会被正确的释放掉,但是我们有时候更关心运行中的内存使用情况。

  只要一个变量的引用计数不为0,gc就无法回收他,也许你这个object暂时没用了,却把他加到一个到程序结束才能被释放的arraylist里去,那这块内存在运行中就被浪费掉了。

  java是不存在内存泄露,但是释放的时机也很重要,一个对象对我们来说其实没用了,却被不小心把这个对象的钥匙借给了一个生命周期比他长的对象,对我们来说就是内存泄露。

  可以好好的看看MemoryAnalyze,分析下现在存在的对象,是不是真的都有用,如果有无用的,一定是被哪里引用了。

  小猿终于完成了第一篇java的随笔。java速成一个月之后,下个月就要转战html5了,勿念…………………………

时间: 2024-10-11 17:11:48

java内存优化牛刀小试的相关文章

java内存优化实践

一般在java程序中,内存是个比较头痛的话题.虽然jvm能够通过GC机制很智能地回收资源,但是由于内存的释放都是jvm在进行操作,不恰当的使用会导致java的程序内存持续增大,直至最终OOM(out of memery) 那么,如何对java进行内存优化呢?一方面可以通过调整jvm的一些配置(内存,GC等),从jvm层优化配置:另一方面,从java程序角度,在代码层次上进行优化. 近期,做了些在java程序方面内存优化实践,积累了一些心得,总结如下: 对于资源消耗较大的对象(如数据库连接,Str

关于java内存优化和性能优化

1.没有必要时请不用使用静态变量 使用Java的开发者都知道,当某个对象被定义为stataic变量所引用,这个对象所占有的内存将不会被回收.有时,开发者会将经常调用的对象或者变量定义为static,以便提高程序的运行性能.因此,不是常用到的对象或者变量,不要定义为static类型的变量,尤其是静态类对象的定义,一定要仔细考虑是否有必要.例如 类在加载时,静态变量会加载进方法区,只要类没被回收,静态变量就不会被回收 2.充分利用单例机制 实用单例可以减少对资源的加载,缩短运行的时间,提高系统效率.

探讨深入Java虚拟机之内存优化

上一篇我们讲述了Java虚拟机的体系结构和内存模型,那么我们就不得不说到内存泄露.大家都知道,Java是从C++的基础上发展而来的,而C++程序的很大的一个问题就是内存泄露难以解决,尽管Java的JVM有一套自己的垃圾回收机制来回收内存,在大多数的情况下并不需要java程序开发人员操太多的心,但也是存在泄露问题的,只是比C++小一点.比如说,程序中存在被引用但无用的对象:程序引用了该对象,但后续不会或者不能再使用它,那么它占用的内存空间就浪费了. 我们先来看看GC是如何工作的:监控每一个对象的运

java程序的内存优化

面试常被问java的垃圾回收机制,感觉平时写代码很少用到,但是注重程序的内存优化确实很重要.<EffectiveJava>这本书有几条讲的挺好,拿过来总结下吧. 首先简单的概括下java的内存回收机制. java内存主要是堆内存和栈内存,栈中的内存会在程序运行到所在作用域之外后进行回收.堆中的内存会在没有引用指向的时候,JVM虚拟机在某个时间段根据特定的算法进行回收. 平时写程序注意如下几点,对程序进行内存优化 1.避免创建不必要的对象 a.使用基本类型替代装箱类型(享元模式) b.Strin

java 内存移到堆外!!! Jvm gcih 淘宝优化JVM实践

官方地址 Jvm gcih 出自Jvm  GC-Invisible Heap 什么是GCIH GC-Invisible Heap,简称GCIH,是一种将Java对象从Java堆内移动到堆外,并且可以在JVM间共享这些对象的技术. 为什么要用GCIH GCIH顾名思义就是GC访问不到的堆,它是对JVM内存管理机制的一个有益的补充. 在某些特殊的应用中有大量生命周期很长的对象,在应用运行的整个过程中它们都存在,不需要被GC回收.如果这类对象很多,总体占用内存比例高,那么他们的存在将给GC带来很多不必

Java代码优化方案 J2ME内存优化

Java代码优化方案 J2ME内存优化 从几本书上,N个网站上整理的一些JAVA代码优化方案,最近的项目只有1M内存可用,必须很抠门了~J2ME项目更要注意的 避免内存溢出 l 不用的对象释放(置空) 如 : a不为空时 a=new object()//这句代码执行时将有两个对象存在于内存中 较好的写法是a=null; a=new object(); 不用的对象设置成null l 内存溢出通常发生在构造函数中,在构造函数中变量在要用时再new,用完之后置null 一次性加载所有图片很容易造成内存

Android内存优化1 了解java GC 垃圾回收机制3

引言 接App优化之内存优化(序), 作为App优化系列中内存优化的一个小部分. 由于内存相关知识比较生涩, 内存优化中使用到的相关工具, 也有很多专有名词. 对Java内存管理, GC, Android内存管理, Dalvik/ART等知识有一个理论的认识, 可以让我们更好的使用这些工具, 分析内存问题. 据此, 我们就先从理论入手, 聊聊GC那些事儿. 1, 何为GC GC 是 garbage collection 的缩写, 垃圾回收的意思. 也可以是 Garbage Collector,

Android内存优化1 了解java内存分配 1

开篇废话 今天我们一起来学习JVM的内存分配,主要目的是为我们Android内存优化打下基础. 一直在想以什么样的方式来呈现这个知识点才能让我们易于理解,最终决定使用方法为:图解+源代码分析. 欢迎访问我的个人博客:senduo's blog 希望能在我们平时开发写代码的时候,能够知道当前写的这段代码,内存方面是如何分配的. 我们深知,一个Java程序员在很多时候根本不用操心内存的释放,而是依靠JVM去管理,以前写C++代码的时候,却要时刻记着new的空间要及时释放掉,不然程序很容易出现内存溢出

JVM性能优化系列-(1) Java内存区域

1. Java内存区域 1.1 运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.主要包括:程序计数器.虚拟机栈.本地方法栈.Java堆.方法区(运 行时常量池).直接内存. 程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器.在虚拟机概念模型中,字节码解释器工作时就是通过改变计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等