精华内容
下载资源
问答
  • 展开全部java控制程序执行,使用的是Thread这个类,62616964757a686964616fe78988e69d8331333337613132可以控制程序暂停或者休眠几秒再执行。示例如下:publicabstractclassMyThreadextendsThread{...

    展开全部

    java控制程序执行,使用的是Thread这个类,62616964757a686964616fe78988e69d8331333337613132可以控制程序暂停或者休眠几秒再执行。示例如下:public abstract class MyThread extends Thread {

    private boolean suspend = false;

    private String control = ""; // 只是需要一个对象而已,这个对象没有实际意义

    public void setSuspend(boolean suspend) {

    if (!suspend) {

    synchronized (control) {

    control.notifyAll();

    }

    }

    this.suspend = suspend;

    }

    public boolean isSuspend() {

    return this.suspend;

    }

    public void run() {

    while (true) {

    synchronized (control) {

    if (suspend) {

    try {

    control.wait();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    this.runPersonelLogic();

    }

    }

    protected abstract void runPersonelLogic();

    public static void main(String[] args) throws Exception {

    MyThread myThread = new MyThread() {

    protected void runPersonelLogic() {

    System.out.println("myThead is running");

    }

    };

    myThread.start();

    Thread.sleep(3000);

    myThread.setSuspend(true);

    System.out.println("myThread has stopped");

    Thread.sleep(3000);

    myThread.setSuspend(false);

    }

    }

    展开全文
  • 当前位置:我的异常网» 编程»java gc 项目终止运行java gc 项目终止运行www.myexceptions.net网友分享于:2013-09-03浏览:6次java gc 项目停止运行首先感谢阿宝同学的帮助,我才对这个gc算法的调整有了一定的认识...

    当前位置:我的异常网» 编程 » java gc 项目终止运行

    java gc 项目终止运行

    www.myexceptions.net  网友分享于:2013-09-03  浏览:6次

    java gc 项目停止运行

    首先感谢阿宝同学的帮助,我才对这个gc算法的调整有了一定的认识,而不是停留在过去仅仅了解的阶段。在读过sun的文档和跟阿宝讨论之后,做个小小的总结,如果有谬误,敬请指正。

    CMS,全称Concurrent Low Pause Collector,是jdk1.4后期版本开始引入的新gc算法,在jdk5和jdk6中得到了进一步改进,它的主要适合场景是对响应时间的重要性需求大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。CMS是用于对tenured generation的回收,也就是年老代的回收,目标是尽量减少应用的暂停时间,减少full gc发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。在我们的应用中,因为有缓存的存在,并且对于响应时间也有比较高的要求,因此希望能尝试使用CMS来替代默认的server型JVM使用的并行收集器,以便获得更短的垃圾回收的暂停时间,提高程序的响应性。

    CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:

    初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 重新标记(CMS-remark) -> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。

    其中的1,3两个步骤需要暂停所有的应用程序线程的。第一次暂停从root对象开始标记存活的对象,这个阶段称为初始标记;第二次暂停是在并发标记之后,暂停所有应用程序线程,重新标记并发标记阶段遗漏的对象(在并发标记阶段结束后对象状态的更新导致)。第一次暂停会比较短,第二次暂停通常会比较长,并且 remark这个阶段可以并行标记。

    而并发标记、并发清除、并发重设阶段的所谓并发,是指一个或者多个垃圾回收线程和应用程序线程并发地运行,垃圾回收线程不会暂停应用程序的执行,如果你有多于一个处理器,那么并发收集线程将与应用线程在不同的处理器上运行,显然,这样的开销就是会降低应用的吞吐量。Remark阶段的并行,是指暂停了所有应用程序后,启动一定数目的垃圾回收进程进行并行标记,此时的应用线程是暂停的。

    CMS的young generation的回收采用的仍然是并行复制收集器,这个跟Paralle gc算法是一致的。

    下面是参数介绍和遇到的问题总结,

    1、启用CMS:-XX:+UseConcMarkSweepGC。 咳咳,这里犯过一个低级错误,竟然将+号写成了-号

    2。CMS默认启动的回收线程数目是  (ParallelGCThreads + 3)/4) ,如果你需要明确设定,可以通过-XX:ParallelCMSThreads=20来设定,其中ParallelGCThreads是年轻代的并行收集线程数

    3、CMS是不会整理堆碎片的,因此为了防止堆碎片引起full gc,通过会开启CMS阶段进行合并碎片选项:-XX:+UseCMSCompactAtFullCollection,开启这个选项一定程度上会影响性能,阿宝的blog里说也许可以通过配置适当的CMSFullGCsBeforeCompaction来调整性能,未实践。

    4.为了减少第二次暂停的时间,开启并行remark: -XX:+CMSParallelRemarkEnabled。如果remark还是过长的话,可以开启-XX:+CMSScavengeBeforeRemark选项,强制remark之前开始一次minor gc,减少remark的暂停时间,但是在remark之后也将立即开始又一次minor gc。

    5.为了避免Perm区满引起的full gc,建议开启CMS回收Perm区选项:

    +CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled

    6.默认CMS是在tenured generation沾满68%的时候开始进行CMS收集,如果你的年老代增长不是那么快,并且希望降低CMS次数的话,可以适当调高此值:

    -XX:CMSInitiatingOccupancyFraction=80

    这里修改成80%沾满的时候才开始CMS回收。

    7.年轻代的并行收集线程数默认是(cpu <=

    11413721493.gif ? cpu : 3 + ((cpu * 5) /

    11413721493.gif,如果你希望降低这个线程数,可以通过-XX:ParallelGCThreads= N 来调整。

    8.进入重点,在初步设置了一些参数后,例如:

    Java代码

    -server -Xms1536m -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=64m

    -XX:MaxPermSize=64m -XX:-UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection

    -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSParallelRemarkEnabled

    -XX:SoftRefLRUPolicyMSPerMB=0

    -server -Xms1536m -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=64m

    -XX:MaxPermSize=64m -XX:-UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection

    -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSParallelRemarkEnabled

    -XX:SoftRefLRUPolicyMSPerMB=0

    需要在生产环境或者压测环境中测量这些参数下系统的表现,这时候需要打开GC日志查看具体的信息,因此加上参数:

    -verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/home/test/logs/gc.log

    在运行相当长一段时间内查看CMS的表现情况,CMS的日志输出类似这样:

    Java代码

    4391.322: [GC [1 CMS-initial-mark: 655374K(1310720K)] 662197K(1546688K), 0.0303050 secs] [Times: user=0.02 sys=0.02, real=0.03 secs]

    4391.352: [CMS-concurrent-mark-start]

    4391.779: [CMS-concurrent-mark: 0.427/0.427 secs] [Times: user=1.24 sys=0.31, real=0.42 secs]

    4391.779: [CMS-concurrent-preclean-start]

    4391.821: [CMS-concurrent-preclean: 0.040/0.042 secs] [Times: user=0.13 sys=0.03, real=0.05 secs]

    4391.821: [CMS-concurrent-abortable-preclean-start]

    4392.511: [CMS-concurrent-abortable-preclean: 0.349/0.690 secs] [Times: user=2.02 sys=0.51, real=0.69 secs]

    4392.516: [GC[YG occupancy: 111001 K (235968 K)]4392.516: [Rescan (parallel) , 0.0309960 secs]4392.547: [weak refs processing, 0.0417710 secs] [1 CMS-remark: 655734K(1310720K)] 766736K(1546688K), 0.0932010 secs] [Times: user=0.17 sys=0.00, real=0.09 secs]

    4392.609: [CMS-concurrent-sweep-start]

    4394.310: [CMS-concurrent-sweep: 1.595/1.701 secs] [Times: user=4.78 sys=1.05, real=1.70 secs]

    4394.310: [CMS-concurrent-reset-start]

    4394.364: [CMS-concurrent-reset: 0.054/0.054 secs] [Times: user=0.14 sys=0.06, real=0.06 secs]

    4391.322: [GC [1 CMS-initial-mark: 655374K(1310720K)] 662197K(1546688K), 0.0303050 secs] [Times: user=0.02 sys=0.02, real=0.03 secs]

    4391.352: [CMS-concurrent-mark-start]

    4391.779: [CMS-concurrent-mark: 0.427/0.427 secs] [Times: user=1.24 sys=0.31, real=0.42 secs]

    4391.779: [CMS-concurrent-preclean-start]

    4391.821: [CMS-concurrent-preclean: 0.040/0.042 secs] [Times: user=0.13 sys=0.03, real=0.05 secs]

    4391.821: [CMS-concurrent-abortable-preclean-start]

    4392.511: [CMS-concurrent-abortable-preclean: 0.349/0.690 secs] [Times: user=2.02 sys=0.51, real=0.69 secs]

    4392.516: [GC[YG occupancy: 111001 K (235968 K)]4392.516: [Rescan (parallel) , 0.0309960 secs]4392.547: [weak refs processing, 0.0417710 secs] [1 CMS-remark: 655734K(1310720K)] 766736K(1546688K), 0.0932010 secs] [Times: user=0.17 sys=0.00, real=0.09 secs]

    4392.609: [CMS-concurrent-sweep-start]

    4394.310: [CMS-concurrent-sweep: 1.595/1.701 secs] [Times: user=4.78 sys=1.05, real=1.70 secs]

    4394.310: [CMS-concurrent-reset-start]

    4394.364: [CMS-concurrent-reset: 0.054/0.054 secs] [Times: user=0.14 sys=0.06, real=0.06 secs]

    其中可以看到CMS-initial-mark阶段暂停了0.0303050秒,而CMS-remark阶段暂停了0.0932010秒,因此两次暂停的总共时间是0.123506秒,也就是123毫秒左右。两次短暂停的时间之和在200以下可以称为正常现象。

    但是你很可能遇到两种fail引起full gc:Prommotion failed和Concurrent mode failed。

    Prommotion failed的日志输出大概是这样:

    Java代码

    [ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K(

    166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs]

    [ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K(

    2166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs]

    这个问题的产生是由于救助空间不够,从而向年老代转移对象,年老代没有足够的空间来容纳这些对象,导致一次full gc的产生。解决这个问题的办法有两种完全相反的倾向:增大救助空间、增大年老代或者去掉救助空间。增大救助空间就是调整-XX:SurvivorRatio参数,这个参数是Eden区和Survivor区的大小比值,默认是32,也就是说Eden区是 Survivor区的32倍大小,要注意Survivo是有两个区的,因此Surivivor其实占整个young genertation的1/34。调小这个参数将增大survivor区,让对象尽量在survitor区呆长一点,减少进入年老代的对象。去掉救助空间的想法是让大部分不能马上回收的数据尽快进入年老代,加快年老代的回收频率,减少年老代暴涨的可能性,这个是通过将-XX:SurvivorRatio 设置成比较大的值(比如65536)来做到。在我们的应用中,将young generation设置成256M,这个值相对来说比较大了,而救助空间设置成默认大小(1/34),从压测情况来看,没有出现prommotion failed的现象,年轻代比较大,从GC日志来看,minor gc的时间也在5-20毫秒内,还可以接受,因此暂不调整。

    Concurrent mode failed的产生是由于CMS回收年老代的速度太慢,导致年老代在CMS完成前就被沾满,引起full gc,避免这个现象的产生就是调小-XX:CMSInitiatingOccupancyFraction参数的值,让CMS更早更频繁的触发,降低年老代被沾满的可能。我们的应用暂时负载比较低,在生产环境上年老代的增长非常缓慢,因此暂时设置此参数为80。在压测环境下,这个参数的表现还可以,没有出现过Concurrent mode failed。

    参考资料:

    《JDK5.0垃圾收集优化之--Don't Pause》 by 江南白衣

    《记一次Java GC调整经历》1,2 by Arbow

    Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning

    Tuning Garbage Collection with the 5.0 JavaTM Virtual Machine

    文章评论

    展开全文
  • 我有一个应用程序,我想暂停一下.重要的是,在两个自动交互之间使图形元素/更改更清晰可见.我尝试使用上面的代码暂停2分钟,但它会导致方法开始时暂停,而不是在方法内的2行精确代码行之间.try {Thread.sleep(2000);} ...

    我有一个应用程序,我想暂停一下.重要的是,在两个自动交互之间使图形元素/更改更清晰可见.

    我尝试使用上面的代码暂停2分钟,但它会导致方法开始时暂停,而不是在方法内的2行精确代码行之间.

    try {

    Thread.sleep(2000);

    } catch(InterruptedException ex) {

    Thread.currentThread().interrupt();

    }

    解决方法:

    Libgdx期望渲染循环定期运行(大致以屏幕刷新率)并且每次都重新绘制屏幕.因为,当您的应用可能“看起来”暂停时,它实际上不应该暂停.它应该忙于更新屏幕,更新动画,响应后退键等.

    因此,您需要更明确地决定在此窗口期间阻止的内容.只是回应输入?添加新元素?然后你应该在窗口中跳过这些元素.

    long endPauseTime = 0;

    当您决定要暂停时:

    endPauseTime = System.currentTimeMillis() + (2 * 1000); // 2 seconds in the future

    然后在你的渲染calback中:

    if (endPauseTime < System.currentTimeMillis()) {

    // non-paused mode, so check inputs or whatever

    } else {

    // paused mode, so skip some things ..

    }

    标签:java,android,libgdx

    来源: https://codeday.me/bug/20190702/1360065.html

    展开全文
  • 一、Java垃圾回收概况概括地说,该机制对 JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,永不停息(Nerver...二、内存区域在Java运行时的数据区里,由JV...

    一、Java垃圾回收概况

    概括地说,该机制对 JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,永不停息(Nerver Stop)的保证JVM中的内存空间,放置出现内存泄露和溢出问题

    Java GC机制主要完成3件事:确定哪些内存需要回收,确定什么时候需要执行GC,如何执行GC。

    二、内存区域

    在Java运行时的数据区里,由JVM管理的内存区域分为下图几个模块:

    3e4dec9f1e5c?from=singlemessage

    内存区域.png

    1. 方法区(Method Area):

    在Java虚拟机规范中,将方法区作为堆的一个逻辑部分来对待,但事实 上,方法区并不是堆(Non-Heap);另外,将Java GC的分代收集机制分为3个代:青年代,老年代,永久代,这些将方法区定义为“永久代”,这是因为,对于之前的HotSpot Java虚拟机的实现方式中,将分代收集的思想扩展到了方法区,并将方法区设计成了永久代。不过,除HotSpot之外的多数虚拟机,并不将方法区当做永 久代,HotSpot本身,也计划取消永久代

    方法区是各个线程共享的区域,用于存储已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、编译器即时编译的代码等

    运行时常量池(Runtime Constant Pool)

    是方法区的一部分,用于存储编译期就生成的字面常量、符号引用、翻译出来的直接引用(符号引用就是编码是用字符串表示某个变量、接口的位置,直接引用就是根据符号引用翻译出来的地址,将在类链接阶段完成翻译);运行时常量池除了存储编译期常量外,也可以存储在运行时间产生的常量(比如String类的intern()方法,作用是String维护了一个常量池,如果调用的字符“abc”已经在常量池中,则返回池中的字符串地址,否则,新建一个常量加入池中,并返回地址)

    2. 堆区(Heap):

    在JVM所管理的内存中,堆区是最大的一块,堆区也是Java GC机制所管理的主要内存区域,堆区由所有线程共享,在虚拟机启动时创建。堆区的存在是为了存储对象实例,原则上讲,所有的对象都在堆区上分配内存(不过现代技术里,也不是这么绝对的,也有栈上直接分配的)。

    一般的,根据Java虚拟机规范规定,堆内存需要在逻辑上是连续的(在物理上不需要),在实现时,可以是固定大小的,也可以是可扩展的,目前主 流的虚拟机都是可扩展的。如果在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError:Java heap space异常

    3. 虚拟机栈(JVM Stack)

    一个线程的每个方法在执行的同时,都会创建一个栈帧(Statck Frame),栈帧中存储的有局部变量表、操作站、动态链接、方法出口等,当方法被调用时,栈帧在JVM栈中入栈,当方法执行完成时,栈帧出栈

    局部变量表

    存储着方法的相关局部变量,包括各种基本数据类型,对象的引用,返回地址等,局部变量表是在编译时就已经确定 好的,方法运行所需要分配的空间在栈帧中是完全确定的,在方法的生命周期内都不会改变

    虚拟机栈中定义了两种异常,如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StatckOverFlowError(栈溢出);不过多 数Java虚拟机都允许动态扩展虚拟机栈的大小(有少部分是固定长度的),所以线程可以一直申请栈,知道内存不足,此时,会抛出 OutOfMemoryError(内存溢出)

    每个线程对应着一个虚拟机栈,因此虚拟机栈也是线程私有的。

    4. 程序计数器(Program Counter Register)

    程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器。字节码解释器在工作时,会通过改变这个计数器的值来取下一条语句指令。

    5. 本地方法栈(Native Method Statck):

    本地方法栈在作用,运行机制,异常类型等方面都与虚拟机栈相同,唯一的区别是:虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将本地方法栈与虚拟机栈放在一起使用。

    本地方法栈也是线程私有的。

    6,直接内存(Direct Memory):

    直接内存,就是 JVM以外的机器内存,比如,你有4G的内存,JVM占用了1G,则其余的3G就是直接内存,JDK中有一种基于通道(Channel)和缓冲区 (Buffer)的内存分配方式,将由C语言实现的native函数库分配在直接内存中,用存储在JVM堆中的DirectByteBuffer来引用。 由于直接内存收到本机器内存的限制,所以也可能出现OutOfMemoryError的异常

    三、Java对象的访问方式

    一般来说,一个Java的引用访问涉及到3个内存区域:JVM栈,堆,方法区

    以最简单的本地变量引用:Object obj = new Object()为例:

    Object obj表示一个本地引用,存储在JVM栈的本地变量表中,表示一个reference类型数据;

    new Object()作为实例对象数据存储在堆中;

    堆中还记录了Object类的类型信息(接口、方法、field、对象类型等)的地址,这些地址所执行的数据存储在方法区中

    在Java虚拟机规范中,对于通过reference类型引用访问具体对象的方式并未做规定,目前主流的实现方式主要有两种:

    通过句柄访问

    3e4dec9f1e5c?from=singlemessage

    句柄访问.png

    通过句柄访问的实现方式中,JVM堆中会专门有一块区域用来作为句柄池,存储相关句柄所执行的实例数据地址(包括在堆中地址和在方法区中的地址)。这种实现方法由于用句柄表示地址,因此十分稳定。

    通过直接指针访问

    3e4dec9f1e5c?from=singlemessage

    通过指针访问.png

    通过直接指针访问的方式中,reference中存储的就是对象在堆中的实际地址,在堆中存储的对象信息中包含了在方法区中的相应类型数据。这种方法最大的优势是速度快,在HotSpot虚拟机中用的就是这种方式。

    四、Java内存分配机制

    这里所说的内存分配,主要指的是在堆上的分配,一般的,对象的内存分配都是在堆上进行,但现代技术也支持将对象拆成标量类型(标量类型即原子类型,表示单个值,可以是基本类型或String等),然后在栈上分配,在栈上分配的很少见,我们这里不考虑。

    Java内存分配和回收的机制概括的说,就是:分代分配,分代回收。对象将根据存活的时间被分为:年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation,也就是方法区)

    3e4dec9f1e5c?from=singlemessage

    内存分配.png

    1.年轻代(Young Generation):

    对象被创建时,内存的分配首先发生在年轻代(大对象可以直接 被创建在年老代),大部分的对象在创建后很快就不再使用,因此很快变得不可达,于是被年轻代的GC机制清理掉(IBM的研究表明,98%的对象都是很快消 亡的),这个GC机制被称为Minor GC或叫Young GC。注意,Minor GC并不代表年轻代内存不足,它事实上只表示在Eden区上的GC

    年轻代上的内存分配是这样的,年轻代可以分为3个区域:Eden区(伊甸园)和两个存活区(Survivor 0 、Survivor 1)。内存分配过程为

    3e4dec9f1e5c?from=singlemessage

    内存分配过程.png

    绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡。Eden区是连续的内存空间,因此在其上分配内存极快;

    当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的);

    此后,每次Eden区满了,就执行一次Minor GC,并将剩余的对象都添加到Survivor0;

    当Survivor0也满的时候,将其中仍然活着的对象直接复制到Survivor1,以后Eden区执行Minor GC后,就将剩余的对象添加Survivor1(此时,Survivor0是空白的)

    当两个存活区切换了几次(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代)之后,仍然存活的对象(其实只有一小部分,比如,我们自己定义的对象),将被复制到老年代。

    从上面的过程可以看出,Eden区是连续的空间,且Survivor总有一个为空。经过一次GC和复制,一个Survivor中保存着当前还活 着的对象,而Eden区和另一个Survivor区的内容都不再需要了,可以直接清空,到下一次GC时,两个Survivor的角色再互换。因此,这种方 式分配内存和清理内存的效率都极高,这种垃圾回收的方式就是著名的“停止-复制(Stop-and-copy)”清理法(将Eden区和一个Survivor中仍然存活的对象拷贝到另一个Survivor中),这不代表着停止复制清理法很高效,其实,它也只在这种情况下高效,如果在老年代采用停止复制,则挺悲剧的。

    在Eden区,HotSpot虚拟机使用了两种技术来加快内存分配。分别是bump-the-pointer和TLAB(Thread- Local Allocation Buffers),这两种技术的做法分别是:由于Eden区是连续的,因此bump-the-pointer技术的核心就是跟踪最后创建的一个对象,在对 象创建时,只需要检查最后一个对象后面是否有足够的内存即可,从而大大加快内存分配速度;而对于TLAB技术是对于多线程而言的,将Eden区分为若干 段,每个线程使用独立的一段,避免相互影响。TLAB结合bump-the-pointer技术,将保证每个线程都使用Eden区的一段,并快速的分配内 存

    2.年老代(Old Generation):

    对象如果在年轻代存活了足够长的时间而没有被清理掉(即在几次 Young GC后存活了下来),则会被复制到年老代,年老代的空间一般比年轻代大,能存放更多的对象,在年老代上发生的GC次数也比年轻代少。当年老代内存不足时, 将执行Major GC,也叫 Full GC。

    可以使用-XX:+UseAdaptiveSizePolicy开关来控制是否采用动态控制策略,如果动态控制,则动态调整Java堆中各个区域的大小以及进入老年代的年龄。

    如果对象比较大(比如长字符串或大数组),Young空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象)。用-XX:PretenureSizeThreshold来控制直接升入老年代的对象大小,大于这个值的对象会直接分配在老年代上。

    可能存在年老代对象引用新生代对象的情况,如果需要执行Young GC,则可能需要查询整个老年代以确定是否可以清理回收,这显然是低效的。解决的方法是,年老代中维护一个512 byte的块——”card table“,所有老年代对象引用新生代对象的记录都记录在这里。Young GC时,只要查这里即可,不用再去查全部老年代,因此性能大大提高。

    3.永久代(Permanent Generation ,也就是方法区)

    五、Java GC机制

    GC机制的基本算法是:分代收集

    年轻代:停止-复制

    在新生代中,使用“停止-复制”算法进行清理,将新生代内存分为2部分,1部分 Eden区较大,1部分Survivor比较小,并被划分为两个等量的部分。每次进行清理时,将Eden区和一个Survivor中仍然存活的对象拷贝到 另一个Survivor中,然后清理掉Eden和刚才的Survivor。

    这里也可以发现,停止复制算法中,用来复制的两部分并不总是相等的(传统的停止复制算法两部分内存相等,但新生代中使用1个大的Eden区和2个小的Survivor区来避免这个问题)

    由于绝大部分的对象都是短命的,甚至存活不到Survivor中,所以,Eden区与Survivor的比例较大,HotSpot默认是 8:1,即分别占新生代的80%,10%,10%。如果一次回收中,Survivor+Eden中存活下来的内存超过了10%,则需要将一部分对象分配到 老年代。用-XX:SurvivorRatio参数来配置Eden区域Survivor区的容量比值,默认是8,代表Eden:Survivor1:Survivor2=8:1:1.

    老年代:标记-整理

    老年代存储的对象比年轻代多得多,而且不乏大对象,对老年代进行内存清理时,如果使用停止-复制算法,则相当低效。一般,老年代用的算法是标记-整理算法,即:标记出仍然存活的对象(存在引用的),将所有存活的对象向一端移动,以保证内存的连续。

    在发生Minor GC时,虚拟机会检查每次晋升进入老年代的大小是否大于老年代的剩余空间大小,如果大于,则直接触发一次Full GC,否则,就查看是否设 置了-XX:+HandlePromotionFailure(允许担保失败),如果允许,则只会进行MinorGC,此时可以容忍内存分配失败;如果不 允许,则仍然进行Full GC(这代表着如果设置-XX:+Handle PromotionFailure,则触发MinorGC就会同时触发Full GC,哪怕老年代还有很多内存,所以,最好不要这样做)。

    方法区(永久代):

    永久代的回收有两种:常量池中的常量,无用的类信息,常量的回收很简单,没有引用了就可以被回收。对于无用的类进行回收,必须保证3点:

    类的所有实例都已经被回收

    加载类的ClassLoader已经被回收

    类对象的Class对象没有被引用(即没有通过反射引用该类的地方)

    永久代的回收并不是必须的,可以通过参数来设置是否对类进行回收。HotSpot提供-Xnoclassgc进行控制

    使用-verbose,-XX:+TraceClassLoading、-XX:+TraceClassUnLoading可以查看类加载和卸载信息

    -verbose、-XX:+TraceClassLoading可以在Product版HotSpot中使用;

    -XX:+TraceClassUnLoading需要fastdebug版HotSpot支持

    六 GC的对象

    需要进行回收的对象就是已经没有存活的对象,判断一个对象是否存活常用的有两种办法:引用计数和可达分析。

    1.引用计数:

    每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题。

    2可达性分析(Reachability Analysis):

    从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。不可达对象。

    在Java语言中,GC Roots包括:

    虚拟机栈中引用的对象。

    方法区中类静态属性实体引用的对象。

    方法区中常量引用的对象。

    本地方法栈中JNI引用的对象。

    七 什么时候触发GC

    (1)程序调用System.gc时可以触发

    (2)系统自身来决定GC触发的时机(根据Eden区和From Space区的内存大小来决定。当内存大小不足时,则会启动GC线程并停止应用线程)

    GC又分为 minor GC 和 Full GC (也称为 Major GC )

    Minor GC触发条件:当Eden区满时,触发Minor GC。

    Full GC触发条件:

    1. 调用System.gc时,系统建议执行Full GC,但是不必然执行

    2. 老年代空间不足

    3. 方法去空间不足

    4. 通过Minor GC后进入老年代的平均大小大于老年代的可用内存

    5. 由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

    八 GC常用算法

    GC常用算法有:标记-清除算法,标记-压缩算法,复制算法,分代收集算法。

    目前主流的JVM(HotSpot)采用的是分代收集算法。

    1 标记-清除算法

    为每个对象存储一个标记位,记录对象的状态(活着或是死亡)。分为两个阶段,一个是标记阶段,这个阶段内,为每个对象更新标记位,检查对象是否死亡;第二个阶段是清除阶段,该阶段对死亡的对象进行清除,执行 GC 操作。

    优点

    最大的优点是,标记—清除算法中每个活着的对象的引用只需要找到一个即可,找到一个就可以判断它为活的。此外,更重要的是,这个算法并不移动对象的位置。

    缺点

    它的缺点就是效率比较低(递归与全堆对象遍历)。每个活着的对象都要在标记阶段遍历一遍;所有对象都要在清除阶段扫描一遍,因此算法复杂度较高。没有移动对象,导致可能出现很多碎片空间无法利用的情况。

    图例

    3e4dec9f1e5c?from=singlemessage

    标记-清除.png

    2 标记-压缩算法(标记-整理)

    标记-压缩法是标记-清除法的一个改进版。同样,在标记阶段,该算法也将所有对象标记为存活和死亡两种状态;不同的是,在第二个阶段,该算法并没有直接对死亡的对象进行清理,而是将所有存活的对象整理一下,放到另一处空间,然后把剩下的所有对象全部清除。这样就达到了标记-整理的目的。

    优点

    该算法不会像标记-清除算法那样产生大量的碎片空间。

    缺点

    如果存活的对象过多,整理阶段将会执行较多复制操作,导致算法效率降低。

    图例

    3e4dec9f1e5c?from=singlemessage

    标记-整理.png

    左边是标记阶段,右边是整理之后的状态。可以看到,该算法不会产生大量碎片内存空间。

    3 复制算法

    该算法将内存平均分成两部分,然后每次只使用其中的一部分,当这部分内存满的时候,将内存中所有存活的对象复制到另一个内存中,然后将之前的内存清空,只使用这部分内存,循环下去。

    注意:

    这个算法与标记-整理算法的区别在于,该算法不是在同一个区域复制,而是将所有存活的对象复制到另一个区域内。

    优点

    实现简单;不产生内存碎片

    缺点

    每次运行,总有一半内存是空的,导致可使用的内存空间只有原来的一半。

    图例

    3e4dec9f1e5c?from=singlemessage

    复制.png

    4 分代收集算法

    现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生代(Young)和老年代(Tenure)。在新生代中,由于对象生存期短,每次回收都会有大量对象死去,那么这时就采用复制算法。老年代里的对象存活率较高,没有额外的空间进行分配担保,所以可以使用标记-整理 或者 标记-清除。

    具体过程:新生代(Young)分为Eden区,From区与To区

    3e4dec9f1e5c?from=singlemessage

    YoungGC.png

    当系统创建一个对象的时候,总是在Eden区操作,当这个区满了,那么就会触发一次YoungGC,也就是年轻代的垃圾回收。一般来说这时候不是所有的对象都没用了,所以就会把还能用的对象复制到From区。

    3e4dec9f1e5c?from=singlemessage

    YoungGC1.png

    这样整个Eden区就被清理干净了,可以继续创建新的对象,当Eden区再次被用完,就再触发一次YoungGC,然后呢,注意,这个时候跟刚才稍稍有点区别。这次触发YoungGC后,会将Eden区与From区还在被使用的对象复制到To区,

    3e4dec9f1e5c?from=singlemessage

    2YoungGC.png

    再下一次YoungGC的时候,则是将Eden区与To区中的还在被使用的对象复制到From区。

    3e4dec9f1e5c?from=singlemessage

    3YoungGC.png

    经过若干次YoungGC后,有些对象在From与To之间来回游荡,这时候From区与To区亮出了底线(阈值),这些家伙要是到现在还没挂掉,对不起,一起滚到(复制)老年代吧。

    3e4dec9f1e5c?from=singlemessage

    4YoungGC.png

    老年代经过这么几次折腾,也就扛不住了(空间被用完),好,那就来次集体大扫除(Full GC),也就是全量回收。如果Full GC使用太频繁的话,无疑会对系统性能产生很大的影响。所以要合理设置年轻代与老年代的大小,尽量减少Full GC的操作。

    九 垃圾收集器

    在GC机制中,起重要作用的是垃圾收集器,垃圾收集器是GC的具体实现,Java虚拟机规范中对于垃圾收集器没有任何规定,所以不同厂商实现的垃圾 收集器各不相同,HotSpot 1.6版使用的垃圾收集器如下图

    3e4dec9f1e5c?from=singlemessage

    垃圾收集器.jpg

    在介绍垃圾收集器之前,需要明确一点,就是在新生代采用的停止复制算法中,“停 止(Stop-the-world)”的意义是在回收内存时,需要暂停其他所 有线程的执行。这个是很低效的,现在的各种新生代收集器越来越优化这一点,但仍然只是将停止的时间变短,并未彻底取消停止。

    Serial收集器:新生代收集器,使用停止复制算法,使用一个线程进行GC,其它工作线程暂停。使用-XX:+UseSerialGC可以使用Serial+Serial Old模式运行进行内存回收(这也是虚拟机在Client模式下运行的默认值)

    ParNew收集器:新生代收集器,使用停止复制算法,Serial收集器的多线程版,用多个线程进行GC,其它工作线程暂停,关注缩短垃圾收集时间。使用-XX:+UseParNewGC开关来控制使用ParNew+Serial Old收集器组合收集内存;使用-XX:ParallelGCThreads来设置执行内存回收的线程数。

    Parallel Scavenge 收集器:新生代收集器,使用停止复制算法,关注CPU吞吐量,即运行用户代码的时间/总时间,比如:JVM运行100分钟,其中运行用户代码99分钟,垃 圾收集1分钟,则吞吐量是99%,这种收集器能最高效率的利用CPU,适合运行后台运算(关注缩短垃圾收集时间的收集器,如CMS,等待时间很少,所以适 合用户交互,提高用户体验)。使用-XX:+UseParallelGC开关控制使用 Parallel Scavenge+Serial Old收集器组合回收垃圾(这也是在Server模式下的默认值);使用-XX:GCTimeRatio来设置用户执行时间占总时间的比例,默认99,即 1%的时间用来进行垃圾回收。使用-XX:MaxGCPauseMillis设置GC的最大停顿时间(这个参数只对Parallel Scavenge有效)

    Serial Old收集器:老年代收集器,单线程收集器,使用标记整理(整理的方法是Sweep(清理)和Compact(压缩),清理是将废弃的对象干掉,只留幸存 的对象,压缩是将移动对象,将空间填满保证内存分为2块,一块全是对象,一块空闲)算法,使用单线程进行GC,其它工作线程暂停(注意,在老年代中进行标 记整理算法清理,也需要暂停其它线程),在JDK1.5之前,Serial Old收集器与ParallelScavenge搭配使用。

    ** Parallel Old收集器:**老年代收集器,多线程,多线程机制与Parallel Scavenge差不错,使用标记整理(与Serial Old不同,这里的整理是Summary(汇总)和Compact(压缩),汇总的意思就是将幸存的对象复制到预先准备好的区域,而不是像Sweep(清 理)那样清理废弃的对象)算法,在Parallel Old执行时,仍然需要暂停其它线程。Parallel Old在多核计算中很有用。Parallel Old出现后(JDK 1.6),与Parallel Scavenge配合有很好的效果,充分体现Parallel Scavenge收集器吞吐量优先的效果。使用-XX:+UseParallelOldGC开关控制使用Parallel Scavenge +Parallel Old组合收集器进行收集。

    CMS(Concurrent Mark Sweep)收集器:老年代收集器,致力于获取最短回收停顿时间,使用标记清除算法,多线程,优点是并发收集(用户线程可以和GC线程同时工作),停顿小。使用-XX:+UseConcMarkSweepGC进行ParNew+CMS+Serial Old进行内存回收,优先使用ParNew+CMS(原因见后面),当用户线程内存不足时,采用备用方案Serial Old收集。

    展开全文
  • 我在这里列出了我的问题http://programtalk.com/java/executorservice-not-shutting-down/如果您正在执行某些IO操作,请小心执行程序服务可能不会立即关闭.如果你看到下面的代码,stopThread很重要,因为它告诉你的程序...
  • (二)java 线程运行暂停、停止

    千次阅读 2018-06-03 18:38:14
    在开始本文之前,需要了解线程的状态,分别是: //更详细的解释可以见源码 Thread.class 中的 State ... RUNNABLE,//运行状态 BLOCKED,//阻塞状态 WAITING,//等待状态 TIMED_WAITING,//有时间限制的...
  • importjava.awt.*;importjava.util.Date;importjava.text.SimpleDateFormat;importjava.util.*;importjava.awt.event.*;publicclassRunTimeimplementsActionListener{Framef1=newFram...import java.awt.*;import ja...
  • Java实现线程“暂停”和“继续”的功能。虽然suspend方法和resume方法已经过时,但是感觉实现起来比较方便。当然,前提是程序不是很复杂,不会出现死锁。下面便是演示代码,可以直接运行看效果。import java.awt....
  • Hot code replace (HCR) is a debugging technique whereby the EclipseJava debugger transmits new class files over the debugging channel toanother JVM. In the case of Eclipse development, this also appli...
  • 只有按一下鼠标右键或者 Ctrl+C 才能取消选中,程序才会继续运行,如果你的java程序是运行在cmd的,不小心点了下界面,程序就暂停,那非常的难受。 解决方法: 在窗口标题处右击,选中属性,进去。 然后取消...
  • 建议 我们已经看到,由于 JVM GC 和 CFS 调度之间的交互,在 Linux cgroup 中运行Java 应用程序可能会遇到更长的应用程序暂停。为缓解此问题,我们建议您使用以下调整: 充分配置 CPU 资源(即 CFS 配额)。显然,...
  • 答:JAVA 程序会在编译和运行的时候自动的检测可能出现的错误,而且它是一种强类型语言,对于类型的检查很严格,而且它的垃圾回收机制也有效的避免了内存的泄漏。2.为什么说java语言是完全面向对象的?答:因为它不...
  • 本节将介绍一下让线程暂停运行的方法。线程Thread 类中的sleep 方法能够暂停线程运行,Sleep 也就是“休眠”的意思。sleep 方法是Thread 类的静态方法。下面这条语句可以将当前的线程(执行这条语句的线程)暂停约1000...
  • 概念虚拟机:指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 ,是物理机的软件实现。常用的虚拟机有VMWare,Visual Box,Java Virtual Machine(Java虚拟机,简称JVM)。Java...
  • 并发和并行并发并发指的是在同一个时间段发生,即交替执行。例如单核CPU一次只能处理一个程序,但是为...单核CPU不能并行处理多个任务,只能是多个任务在单个CPU上并发运行。并行并行指的两个或者多个事件在同一时...
  • savedInstanceState更适合在状态之间切换,比如暂停/恢复,这种事情.它也必须始终由您创建.像这样的东西:public static final String PREFS_NAME = "MyPrefsFile"; // Name of prefs file; don't change this after ...
  • import java.awt.Image; import java.util.Iterator; import javax.swing.ImageIcon; import javax.swing.JButton; public class Card { int i; String img; Card(int i,String img){ this.i = i; this....
  • 我有一个关于Java TimerTask的简单问题。如何根据一定条件暂停/恢复两个TimerTask任务?例如,我有两个相互之间运行的计时器。当在第一定时器的任务内满足一定条件时,第一定时器停止并启动第二定时器,当在第二...
  • 我必须构建一个脚本来从txt文件读取一些url来检查更新,如果URL没有上次运行脚本时的任何更改,脚本不应该在典型输出中打印任何内容,如果有是脚本应在典型输出(stdout)中打印URL的任何URL的更新(例如 ...
  • 2) 线程是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),一个线程可以...
  • 暂停线程意味着此线程还可以恢复运行。在 Java 多线程中,可以使用 suspend() 方法暂停线程,使用 resume() 方法恢复线程的执行。suspend() 与 resume() 方法本节通过一个案例来介绍 suspend() 与 resume() 方法的...
  • 计划运行之间存在应用程序暂停,预期的应用程序暂停时间为 70 毫秒(假设应用程序完全使用 90 毫秒 CPU 配额)。 Java 和非 Java 应用程序的问题场景 第一个问题发生在应用程序耗尽 90ms 的所有 CPU 配额时,例如在...
  • import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.GridLayout; import java.awt.Robot; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; impor...
  • 正常运行时间和服务运行状态 这一指标奠定了整个应用程序性能的基础。不仅可以当做一个提醒指标,也可以让你定义一段时间内的SKA。我们可以使用Pingdom的servlet功能进行运行状态检查。我们可以查到应用程序的所有...
  • 推荐工具: Grafana The ELK stack Datadog Librato 06正常运行时间和服务运行状态 这一指标奠定了整个应用程序性能的基础。不仅可以当做一个提醒指标,也可以让你定义一段时间内的SKA。我们可以使用Pingdom的...
  • 这是我正在尝试做的事情:我有一个JFrame,其中包含一个JTextArea,用于显示正在进行的连接上的更新.如果用户想要取消连接,则...尽管我可以基本使用可运行对象,但我对线程没有太多经验.答案是否与使用EDT有关?如果...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,477
精华内容 590
关键字:

java暂停运行

java 订阅