java代码优化jvm java代码优化大全

java代码怎么设定启动时的JVM参数不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确java代码优化jvm的选择不同的GC策略,调整JVM、GC的参数java代码优化jvm,可以极大的减少由于GC工作,而导致的程序运行中断方面的问题,进而适当的提高Java程序的工作效率 。但是调整GC是以个极为复杂的过程,由于各个程序具备不同的特点
jvm是如何实现的编程语言和自然语言类似 , 都是为了交流,自然语言用于跟人交流,程序语言则用于指示机器 。
jvm其实也就是一个程序,这个程序能接受你的Java代码,然后根据你的意愿执行一系列操作 。
举个例子,你可以写一个这样的程序,这个程序接受用户输入一句话 , 如果用户输入“beep”则调用机器的鸣叫,如果用户输入“exit” , 则关掉本程序 。在这个例子中,其实用户写的“beep”和“exit”就充当了程序语言的角色,只不过这门语言过于简单因此不可能普及 。而java则具有完善的体系能够支持你表达任何意愿,然后jvm理解你的java语言并执行相应操作 , 这就是程序语言的原理 。
当然java还有优化的方案,它的编译器将你的java语言翻译成字节码,因为jvm执行字节码的速度比直接理解java代码要快很多,后来的版本还引入了JIT技术,实时将字节码再编译成机器码,这样就能让机器直接执行指令而不需要jvm去解释 。
至于垃圾收集器,就是jvm维护着每一个对象的引用(可以理解成C里面的指针),根据一定的算法判断其是否可达,如果这个引用不可达(也就是程序的后续部分已经无法获取这个引用,比如说已超出block范围了)那么就清除这个内存对象 。这样的好处是能避免由于程序员的疏忽引起的内存泄露,缺点是内存的清理不够即时,因而无用的对象常常会占据内存很长时间 。
你也可以在C里实现垃圾回收器,思路是写一个用于管理内存的类,然后程序里不再用new来新建对象,而是用这个类来产生对象,类内部拥有这个对象的指针,并在适当的时候delete它 , 这样就实现垃圾自动回收了 , 当然要写这样一个类是很困难的事 。
JVM原理是什么?首先这里澄清两个概念:JVM实例和JVM执行引擎实例,JVM实例对应了一个独立运行的Java程序,而JVM执行引擎实例则对应了属于用户运行程序的线程;也就是JVM实例是进程级别 , 而执行引擎是线程级别的 。JVM是什么?—JVM的生命周期JVM实例的诞生:当启动一个Java程序时,一个JVM实例就产生了,任何一个拥有publicstaticvoidmain(String[]args)函数的class都可以作为JVM实例运行的起点 , 既然如此,那么JVM如何知道是运行classA的main而不是运行classB的main呢?这就需要显式的告诉JVM类名,也就是我们平时运行Java程序命令的由来,如JavaclassAhelloworld,这里Java是告诉os运行SunJava2SDK的Java虚拟机 , 而classA则指出了运行JVM所需要的类名 。JVM实例的运行:main()作为该程序初始线程的起点,任何其他线程均由该线程启动 。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,Java程序也可以标明自己创建的线程是守护线程 。JVM实例的消亡:当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出 。JVM是什么?—JVM的体系结构粗略分来,JVM的内部体系结构分为三部分,分别是:类装载器(ClassLoader)子系统,运行时数据区,和执行引擎 。下面将先介绍类装载器,然后是执行引擎,最后是运行时数据区1、类装载器 , 顾名思义,就是用来装载.class文件的 。JVM的两种类装载器包括:启动类装载器和用户自定义类装载器 , 启动类装载器是JVM实现的一部分,用户自定义类装载器则是Java程序的一部分,必须是ClassLoader类的子类 。(下面所述情况是针对SunJDK1.2)动类装载器:只在系统类(JavaAPI的类文件)的安装路径查找要装入的类用户自定义类装载器:系统类装载器:在JVM启动时创建 , 用来在CLASSPATH目录下查找要装入的类其他用户自定义类装载器:这里有必要先说一下ClassLoader类的几个方法,了解它们对于了解自定义类装载器如何装载.class文件至关重要 。protectedfinalClassdefineClass(Stringname,bytedata[],intoffset,intlength) protectedfinalClassdefineClass(Stringname,bytedata[],intoffset,intlength,ProtectionDomainprotectionDomain);protectedfinalClassfindSystemClass(Stringname) protectedfinalvoidresolveClass(Classc) defineClass用来将二进制class文件(新类型)导入到方法区,也就是这里指的类是用户自定义的类(也就是负责装载类)findSystemClass通过类型的全限定名 , 先通过系统类装载器或者启动类装载器来装载,并返回Class对象 。ResolveClass:让类装载器进行连接动作(包括验证,分配内存初始化,将类型中的符号引用解析为直接引用),这里涉及到Java命名空间的问题,JVM保证被一个类装载器装载的类所引用的所有类都被这个类装载器装载,同一个类装载器装载的类之间可以相互访问,但是不同类装载器装载的类看不见对方 , 从而实现了有效的屏蔽 。2、执行引擎:它或者在执行字节码,或者执行本地方法要说执行引擎,就不得不的指令集,每一条指令包含一个单字节的操作码,后面跟0个或者多个操作数 。(一)指令集以栈为设计中心,而非以寄存器为中心这种指令集设计如何满足Java体系的要求:平台无关性:以栈为中心使得在只有很少register的机器上实现Java更便利compiler一般采用stack向连接优化器传递编译的中间结果,若指令集以stack为基础,则有利于运行时进行的优化工作与执行即时编译或者自适应优化的执行引擎结合,通俗的说就是使编译和运行用的数据结构统一,更有利于优化的开展 。网络移动性:class文件的紧凑性 。安全性:指令集中绝大部分操作码都指明了操作的类型 。(在装载的时候使用数据流分析期进行一次性验证,而非在执行每条指令的时候进行验证,有利于提高执行速度) 。(二)执行技术主要的执行技术有:解释,即时编译,自适应优化、芯片级直接执行其中解释属于第一代JVM , 即时编译JIT属于第二代JVM,自适应优化(目前Sun的HotspotJVM采用这种技术)则吸取第一代JVM和第二代JVM的经验,采用两者结合的方式自适应优化:开始对所有的代码都采取解释执行的方式 , 并监视代码执行情况 , 然后对那些经常调用的方法启动一个后台线程,将其编译为本地代码,并进行仔细优化 。若方法不再频繁使用,则取消编译过的代码 , 仍对其进行解释执行 。3、运行时数据区:主要包括:方法区,堆 , Java栈 , PC寄存器,本地方法栈(1)方法区和堆由所有线程共享堆:存放所有程序在运行时创建的对象方法区:当JVM的类装载器加载.class文件,并进行解析,把解析的类型信息放入方法区 。(2)Java栈和PC寄存器由线程独享 , 在新线程创建时间里(3)本地方法栈:存储本地方法调用的状态上边总体介绍了运行时数据区的主要内容 , 下边进行详细介绍,要介绍数据区,就不得不说明JVM中的数据类型 。JVM中的数据类型:JVM中基本的数据单元是word,而word的长度由JVM具体的实现者来决定数据类型包括基本类型和引用类型 , (1)基本类型包括:数值类型(包括除boolean外的所有的Java基本数据类型),boolean(在JVM中使用int来表示,0表示false,其他int值均表示true)和returnAddress(JVM的内部类型,用来实现finally子句) 。(2)引用类型包括:数组类型,类类型,接口类型前边讲述了JVM中数据的表示 , 下面让我们输入到JVM的数据区首先来看方法区:上边已经提到,方法区主要用来存储JVM从class文件中提取的类型信息,那么类型信息是如何存储的呢?众所周知,Java使用的是大端序(big?endian:即低字节的数据存储在高位内存上,如对于1234,12是高位数据 , 34为低位数据,则Java中的存储格式应该为12存在内存的低地址,34存在内存的高地址,x86中的存储格式与之相反)来存储数据,这实际上是在class文件中数据的存储格式,但是当数据倒入到方法区中时,JVM可以以任何方式来存储它 。类型信息:包括class的全限定名,class的直接父类,类类型还是接口类型,类的修饰符(public,等),所有直接父接口的列表,Class对象提供了访问这些信息的窗口(可通过Class.forName(“”)或instance.getClass()获得),下面是Class的方法,相信大家看了会恍然大悟,(原来如此J)getName(),getSuperClass(),isInterface(),getInterfaces(),getClassLoader();static变量作为类型信息的一部分保存指向ClassLoader类的引用:在动态连接时装载该类中引用的其他类指向Class类的引用:必然的,上边已述该类型的常量池:包括直接常量(String , integer和floatpoint常量)以及对其他类型、字段和方法的符号引用(注意:这里的常量池并不是普通意义上的存储常量的地方,这些符号引用可能是我们在编程中所接触到的变量),由于这些符号引用,使得常量池成为Java程序动态连接中至关重要的部分字段信息:普通意义上的类型中声明的字段方法信息:类型中各个方法的信息编译期常量:指用final声明或者用编译时已知的值初始化的类变量class将所有的常量复制至其常量池或者其字节码流中 。方法表:一个数组,包括所有它的实例可能调用的实例方法的直接引用(包括从父类中继承来的)除此之外,若某个类不是抽象和本地的 , 还要保存方法的字节码,操作数栈和该方法的栈帧,异常表 。举例:classLava{ privateintspeed=5; voidflow(){} classVolcano{ publicstaticvoidmain(String[]args){ Lavalava=newLava(); lava.flow(); } } 运行命令JavaVolcano;(1)JVM找到Volcano.class倒入,并提取相应的类型信息到方法区 。通过执行方法区中的字节码,JVM执行main()方法,(执行时会一直保存指向Vocano类的常量池的指针)(2)Main()中第一条指令告诉JVM需为列在常量池第一项的类分配内存(此处再次说明了常量池并非只存储常量信息),然后JVM找到常量池的第一项,发现是对Lava类的符号引用,则检查方法区,看Lava类是否装载,结果是还未装载,则查找“Lava.class”,将类型信息写入方法区,并将方法区Lava类信息的指针来替换Volcano原常量池中的符号引用,即用直接引用来替换符号引用 。(3)JVM看到new关键字 , 准备为Lava分配内存,根据Volcano的常量池的第一项找到Lava在方法区的位置,并分析需要多少对空间,确定后 , 在堆上分配空间,并将speed变量初始为0,并将lava对象的引用压到栈中(4)调用lava的flow()方法好了,大致了解了方法区的内容后,让我们来看看堆Java对象的堆实现:Java对象主要由实例变量(包括自己所属的类和其父类声明的)以及指向方法区中类数据的指针,指向方法表的指针 , 对象锁(非必需),等待集合(非必需) , GC相关的数据(非必需)(主要视GC算法而定 , 如对于标记并清除算法,需要标记对象是否被引用,以及是否已调用finalize()方法) 。那么为什么Java对象中要有指向类数据的指针呢?我们从几个方面来考虑首先:当程序中将一个对象引用转为另一个类型时 , 如何检查转换是否允许?需用到类数据其次:动态绑定时,并不是需要引用类型,而是需要运行时类型 , 这里的迷惑是:为什么类数据中保存的是实际类型,而非引用类型?这个问题先留下来,我想在后续的读书笔记中应该能明白指向方法表的指针:这里和C的VTBL是类似的,有利于提高方法调用的效率对象锁:用来实现多个线程对共享数据的互斥访问等待集合:用来让多个线程为完成共同目标而协调功过 。(注意Object类中的wait(),notify(),notifyAll()方法) 。Java数组的堆实现:数组也拥有一个和他们的类相关联的Class实例,具有相同dimension和type的数组是同一个类的实例 。数组类名的表示:如[[LJava/lang/Object表示Object[][],[I表示int[],[[[B表示byte[][][]至此,堆已大致介绍完毕 , 下面来介绍程序计数器和Java栈程序计数器:为每个线程独有,在线程启动时创建 , 若thread执行Java方法,则PC保存下一条执行指令的地址 。若thread执行native方法 , 则Pc的值为undefinedJava栈:Java栈以帧为单位保存线程的运行状态,Java栈只有两种操作,帧的压栈和出栈 。每个帧代表一个方法,Java方法有两种返回方式,return和抛出异常,两种方式都会导致该方法对应的帧出栈和释放内存 。帧的组成:局部变量区(包括方法参数和局部变量,对于instance方法 , 还要首先保存this类型,其中方法参数按照声明顺序严格放置,局部变量可以任意放置),操作数栈,帧数据区(用来帮助支持常量池的解析,正常方法返回和异常处理) 。本地方法栈:依赖于本地方法的实现 , 如某个JVM实现的本地方法借口使用C连接模型,则本地方法栈就是C栈,可以说某线程在调用本地方法时,就进入了一个不受JVM限制的领域,也就是JVM可以利用本地方法来动态扩展本身 。相信大家都明白JVM是什么了吧 。原文链接:
jvm性能调优都做了什么JVM是最好java代码优化jvm的软件工程之一,它为Java提供了坚实的基础 , 许多流行语言如Kotlin、Scala、Clojure、Groovy都使用JVM作为运行基础 。一个专业的Java工程师必须要了解并掌握JVM,接下来就给大家分享Java基础知识中JVM调优相关知识点 。
杭州Java基础知识学习之JVM调优讲解
JVM常见的调优参数包括java代码优化jvm:
-Xmx:指定java程序的最大堆内存, 使用java -Xmx5000M -version判断当前系统能分配的最大堆内存java代码优化jvm;
-Xms:指定最小堆内存, 通常设置成跟最大堆内存一样,减少GC;
-Xmn:设置年轻代大小 。整个堆大小=年轻代大小 年老代大小 。所以增大年轻代后,将会减小年老代大小 。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8;
-Xss:指定线程的最大栈空间, 此参数决定了java函数调用的深度, 值越大调用深度越深, 若值太小则容易出栈溢出错误(StackOverflowError);
-XX:PermSize:指定方法区(永久区)的初始值,默认是物理内存的1/64,在Java8永久区移除, 代之的是元数据区 , 由-XX:MetaspaceSize指定;
-XX:MaxPermSize:指定方法区的最大值, 默认是物理内存的1/4,在java8中由-XX:MaxMetaspaceSize指定元数据区的大?。?
-XX:NewRatio=n:年老代与年轻代的比值,-XX:NewRatio=2, 表示年老代与年轻代的比值为2:1;
-XX:SurvivorRatio=n:Eden区与Survivor区的大小比值 , -XX:SurvivorRatio=8表示Eden区与Survivor区的大小比值是8:1:1,因为Survivor区有两个(from, to) 。
JVM实质上分为三大块,年轻代(YoungGen),年老代(Old Memory),及持久代(Perm,在Java8中被取消) 。
年轻代大小选择
响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择) 。在此种情况下,年轻代收集发生的频率也是最小的 。同时,减少到达年老代的对象 。
吞吐量优先的应用:尽可能的设置大 , 可能到达Gbit的程度 。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用 。
年老代大小选择
响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数 。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间 。最优化的方案,一般需要参考以下数据获得:并发垃圾收集信息、持久代并发收集次数、传统GC信息、花在年轻代和年老代回收上的时间比例 。
减少年轻代和年老代花费的时间,一般会提高应用的效率 。
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代 。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象 。
较小堆引起的碎片问题
因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩 。当收集器回收时,java代码优化jvm他会把相邻的空间进行合并,这样可以分配给较大的对象 。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止 , 然后使用传统的标记、清除方式进行回收 。如果出现“碎片”,可能需要进行如下配置:
-XX: UseCMSCompactAtFullCollection:使用并发收集器时 , 开启对年老代的压缩 。
-XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩 。
JVM 对Java 的原生锁做了哪些优化以前是用sychronize关键字来做的java代码优化jvm,后来改成java代码优化jvm了基于CAS的锁 。。。
【java代码优化jvm java代码优化大全】关于java代码优化jvm和java代码优化大全的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息 , 记得收藏关注本站 。

    推荐阅读