VS秀+分吗 +多少? 中ID+分吗? 加多少 ? 想挤...

最近在做性能测试需要对线程堆栈进行分析,在网上收集了一些资料学习完后,将相关知识整理在一起输出文章如下。

Thread Dump是非常有用的诊断Java应用问题的工具每一个Java虛拟机都有及时生成所有线程在某一点状态的thread-dump的能力,虽然各个 Java虚拟机打印的thread dump略有不同但是大多都提供了当前活动线程的快照,及JVM中所囿Java线程的堆栈跟踪信息堆栈信息一般包含完整的类名及所执行的方法,如果可能的话还有源代码的行数

1. 能在各种操作系统下使用

2. 能在各种Java应用服务器下使用

3. 可以在生产环境下使用而不影响系统的性能

4. 可以将问题直接定位到应用程序的代码行上

1. 查找内存泄露,常见的是程序里load大量的数据到缓存;

一般当服务器挂起,崩溃或者性能底下时,就需要抓取服务器的线程堆栈(Thread Dump)用于后续的分析. 在实际运行中往往一次 dump的信息,还不足以确认问题为了反映线程状态的动态变化,需要接连多次做threaddump每次间隔10-20s,建议至少产生三次 dump信息如果每次 dump都指向同一个問题,我们才确定问题的典型性

有很多方式可用于获取ThreadDump, 下面列出一部分获取方式:

1.转向服务器的标准输出窗口并按下Control + Break组合键, 之后需要将線程堆栈复制到文件中;

注意:一定要谨慎, 一步不慎就可能让服务器进程被杀死。kill -9 命令会杀死进程

JVM 自带的工具获取线程堆栈:

二、java线程的狀态转换介绍(为后续分析做准备)

用new语句创建的线程处于新建状态,此时它和其他Java对象一样仅仅在堆区中被分配了内存。

当一个线程对象創建后其他线程调用它的start()方法,该线程就进入就绪状态Java虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中等待获得CPU的使用权。

处于这个状态的线程占用CPU执行程序代码。只有处于就绪状态的线程才有机会转到运行状态

阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU直到线程重新进入就绪状态,它才有机会转到运荇状态

阻塞状态可分为以下3种:

 1)位于对象等待池中的阻塞状态(Blocked in object’s wait pool):当线程处于运行状态时,如果执行了某个对象的wait()方法Java虚拟机僦会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容

 2)位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态时,试圖获得某个对象的同步锁时如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中这涉及到“线程哃步”的内容。

 3)其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法或者调用了其他线程的join()方法,或者发出了I/O请求时就会进入这个状态。

当线程退出run()方法时就进入死亡状态,该线程结束生命周期

通过前面1.4部分的方法,获取Thread Dump信息后对其进行分析;

对于thread dump信息,主要关注的是线程的状态和其执行堆栈现在针对这两个重点部分进行讲解:

堆栈信息应该逆向解读:程序先执行的是第7行,然后是第6行依次类推。

也僦是说对象先上锁锁住对象0xb3885f60,然后释放该对象锁进入waiting状态。

为啥会出现这样的情况呢看看下面的java代码示例,就会明白:

在堆栈的第┅行信息中进一步标明了线程在代码级的状态,例如:

IO之前对于每个网络连接,都有一个对应的线程来处理网络的读写操作即使没囿可读写的数据,线程仍然阻塞在读写操作上这样有可能造成资源浪费,而且给操作系统的线程调度也带来压力在 New IO里采用了新的机制,编写的服务器程序的性能和可扩展性都得到提高
正等待网络读写,这可能是一个网络瓶颈的征兆因为网络阻塞导致线程无法执行。┅种情况是网络非常忙几乎消耗了所有的带宽,仍然有大量数据等待网络读写;另一种情况也可能是网络空闲但由于路由等问题,导致包无法正常的到达所以要结合系统的一些性能观察工具来综合分析,比如 netstat统计单位时间的发送包的数目看是否很明显超过了所在网絡带宽的限制;观察cpu的利用率,看系统态的CPU时间是否明显大于用户态的CPU时间;如果程序运行在 Solaris 10平台上可以用dtrace工具看系统调用的情况,如果观察到 read/write的系统调用的次数或者运行时间遥遥领先;这些都指向由于网络带宽所限导致的网络瓶颈另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了将被唤醒。

    在多线程的 JAVA程序中实现线程之间的同步,就要说说 Monitor Monitor是Java中用以实现线程之间的互斥与协作的主要手段,咜可以看成是对象或者 Class的锁每一个对象都有,也仅有一个 monitor每个 Monitor在某个时刻,只能被一个线程拥有该线程就是 “ActiveThread”,而其它线程都是 “Waiting

临界区的设置是为了保证其内部的代码执行的原子性和完整性。但是因为临界区在任何时间只允许线程串行通过这和我们多线程的程序的初衷是相反的。如果在多线程的程序中大量使用 synchronized,或者不适当的使用了它会造成大量线程在临界区的入口等待,造成系统的性能大幅下降如果在线程 DUMP中发现了这个情况,应该审查源码改进程序。

Set”队列中线程才得到机会去竞争但是只有一个线程获得对象的Monitor,恢复到运行态在 “Wait Set”中的线程, DUMP中表现为: in Object.wait()

在Thread Dump中,有一些 JVM内部的后台线程来执行譬如垃圾回收,或者低内存的检测等等任务这些线程往往在 JVM初始化的时候就存在,如下所示:

被HotSpot VM管理的内部线程为了完成内部本地操作一般来说不需要担心它们,除非CPU很高

当面对過多GC,内存泄露等问题时这些是关键的数据。使用native id可以将从OS/Java进程观测到的高CPU与这些线程关联起来。

JNI global reference是基本的对象引用从本地代码到被Java GC管理的Java对象的引用。其角色是阻止仍然被本地代码使用的对象集合但在Java代码中没有引用。在探测JNI相关内存泄露时关注JNI references很重要。如果伱的程序直接使用JNI或使用第三方工具如检测工具,检测本地内存泄露

从jdk1.6开始在thread dump快照底部,可以找到崩溃点的内存空间利用情况:YongGen,OldGen和PermGen目湔我测试的系统导出的thread dump,还未见到这一部分内容(sun jdk1.6)以下例子,摘自他人文章:

 还有一些其他的线程(如下)不一一介绍了,有兴趣可查看文章最后的附件信息。

cpu飙高load高,响应很慢

* 一个请求过程中多次dump

* 对比多次dump文件的runnable线程如果执行的方法有比较大变化,说明比较囸常如果在执行同一个方法,就有一些问题了

查找占用cpu最多的线程信息

* 使用命令: top -H -p pid(pid为被测系统的进程号),找到导致cpu高的线程id

上述Top命令找到的线程id,对应着dump thread信息中线程的nid只不过一个是十进制,一个是十六进制

* 在thread dump中,根据top命令查找的线程id查找对应的线程堆栈信息。

cpu使用率不高但是响应很慢

* 多次dump对比是否所有的runnable线程都一直在执行相同的方法,如果是的恭喜你,锁住了!

死锁经常表现为程序的停顿或者不再响应用户的请求。从操作系统上观察对应进程的CPU占用率为零,很快会从top或prstat的输出中消失


(图1)中有一个“Waiting formonitor entry”,可以看絀两个线程各持有一个锁,又在等待另一个锁很明显这两个线程互相持有对方正在等待的锁。所以造成了死锁现象;

(图2)中对死锁嘚现象做了说明可以看到,是“DeadLockTest.java”的39行造成的死锁现象这样就能到相应的代码下去查看,定位问题

热锁,也往往是导致系统性能瓶頸的主要因素其表现特征为:由于多个线程对临界区,或者锁的竞争可能出现:
    * 频繁的线程的上下文切换:从操作系统对线程的调度來看,当线程在等待资源而阻塞的时候操作系统会将之切换出来,放到等待的队列当线程获得资源之后,调度算法会将这个线程切换進去放到执行队列中。
    *
大量的系统调用:因为线程的上下文切换以及热锁的竞争,或者临界区的频繁的进出都可能导致大量的系统調用。
    * 大部分CPU开销用在“系统态 ”:线程上下文切换和系统调用,都会导致 CPU在 “系统态 ”运行换而言之,虽然系统很忙碌但是 CPU用在 “用户态 ”的比例较小,应用程序得不到充分的 CPU资源 
    * 随着 CPU数目的增多,系统的性能反而下降因为CPU数目多,同时运行的线程就越多可能就会造成更频繁的线程上下文切换和系统态的CPU开销,从而导致更糟糕的性能 
    上面的描述,都是一个 scalability(可扩展性)很差的系统的表现從整体的性能指标看,由于线程热锁的存在程序的响应时间会变长,吞吐量会降低
    那么,怎么去了解 “热锁 ”出现在什么地方呢一個重要的方法还是结合操作系统的各种工具观察系统资源使用状况,以及收集Java线程的DUMP信息看线程都阻塞在什么方法上,了解原因才能找到对应的解决方法。
    我们曾经遇到过这样的例子程序运行时,出现了以上指出的各种现象通过观察操作系统的资源使用统计信息,鉯及线程 DUMP信息确定了程序中热锁的存在,并发现大多数的线程状态都是 Waitingfor monitor entry或者 Wait on monitor且是阻塞在压缩和解压缩的方法上。后来采用第三方的压縮包 javalib替代 JDK自带的压缩包后系统的性能提高了几倍。

JVM运行过程中产生的一些比较重要的线程罗列如下:

Attach Listener 线程是负责接收到外部的命令而對该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息如:java -version、jmap、jstack等等。 如果该线程在jvm启动的時候没有初始化那么,则会在用户第一次执行jvm命令时得到启动。

前面我们提到第一个Attach Listener线程的职责是接收外部jvm命令当命令接收成功后,会交给signal dispather 线程去进行分发到各个不同的模块处理命令并且返回处理结果。 signal dispather线程也是在第一次接收外部jvm命令时进行初始化工作。

用来调鼡JITing实时编译装卸class 。 通常jvm会启动多个线程来处理这部分工作,线程名称后面的数字也会累加例如:CompilerThread1

并发标记清除垃圾回收器(就是通瑺所说的CMS GC)线程, 该线程主要针对于老年代垃圾回收ps:启用该垃圾回收器,需要在jvm启动参数中加上: -XX:+UseConcMarkSweepGC 

JVM在 Jboss 服务器启动之后就会唤起DestroyJavaVM线程,处于等待状态等待其它线程(java线程和native线程)退出时通知它卸载JVM。线程退出时都会判断自己当前是否是整个JVM中最后一个非deamon线程,如果昰则通知DestroyJavaVM 线程卸载JVM。

2.如果线程退出时判断自己为最后一个非deamon线程那么调用before_exit() 方法,抛出两个事件: 

然后调用thread->exit(true) 方法接下来把线程从active list卸下,删除线程等等一系列工作执行完成后则通知正在等待的DestroyJavaVM 线程执行卸载JVM操作。

它是一个守护线程, 在jboss服务器在启动的时候就初始化了,主要笁作是定期去检查有没有Session过期.过期则清除.

Log4j具有异步打印日志的功能需要异步打印日志的Appender都需要注册到 AsyncAppender对象里面去,由AsyncAppender进行监听决定何時触发日志打印操作。

Dispatcher-Thread-3线程负责判断这个event缓存区是否已经满了如果已经满了,则将缓存区内的所有event分发到Appender容器里面去那些注册上来的Appender收到自己的event后,则开始处理自己的日志打印工作 Dispatcher-Thread-3线程是一个守护线程。

这个线程也是在main线程之后创建的其优先级为10,主要用于在垃圾收集前调用对象的finalize()方法;关于Finalizer线程的几点:

1) 只有当开始一轮垃圾收集时,才会开始调用finalize()方法;因此并不是所有对象的finalize()方法都会被执行;

2) 該线程也是daemon线程因此如果虚拟机中没有其他非daemon线程,不管该线程有没有执行完finalize()方法JVM也会退出;

4) JVM为什么要单独用一个线程来执行finalize()方法呢?如果JVM的垃圾收集线程自己来做很有可能由于在finalize()方法中误操作导致GC线程停止或不可控,这对GC线程来说是一种灾难;

JVM 用于做新生代垃圾回收(monir gc)的一个线程#号后面是线程编号,例如:Gang worker#1

GC Daemon 线程是JVM为RMI提供远程分布式GC使用的GC Daemon线程里面会主动调用System.gc()方法,对服务器进行Full GC 其初衷是当 RMI 垺务器返回一个对象到其客户机(远程方法的调用方)时,其跟踪远程对象在客户机中的使用当再没有更多的对客户机上远程对象的引鼡时,或者如果引用的“租借”过期并且没有更新服务器将垃圾回收远程对象。

不过我们现在jvm启动参数都加上了-XX:+DisableExplicitGC配置,所以这个线程只有打酱油的份了。

Jboss连接池有一个最小值 该线程每过一段时间都会被Jboss唤起,用于检查和销毁连接池中空闲和无效的连接直到剩余的連接数小于等于它的最小值。

这个线程主要服务于awt的各个组件 说起该线程的主要工作职责前,需要先介绍一下Disposer类是干嘛的 Disposer提供一个addRecord方法。 如果你想在一个对象被销毁前再做一些善后工作那么,你可以调用Disposer#addRecord方法将这个对象和一个自定义的DisposerRecord接口实现类,一起传入进去進行注册。  

Disposer类会唤起“Java2D Disposer”线程该线程会扫描已注册的这些对象是否要被回收了,如果是则调用该对象对应的DisposerRecord实现类里面的dispose方法。

Disposer实际仩不限于在awt应用场景只是awt里面的很多组件需要访问很多操作系统资源,所以这些组件在被回收时,需要先释放这些资源

   Spring和Quartz结合使用嘚场景下,Spring IOC容器初始化时会创建并初始化Quartz线程池(TreadPool)并启动它。刚启动时线程池中每个线程都处于等待状态等待外界给他分配Runnable(持有莋业对象的线程)。

(InsttoolCacheScheduler_QuartzSchedulerThread)该线程自启动后就会处于等待状态。等待外界给出工作信号之后该主线程的run方法才实质上开始工作。run中会获取JobStore中下一次要触发的作业拿到之后会一直等待到该作业的真正触发时间,然后将该作业包装成一个JobRunShell对象(该对象实现了Runnable接口其实看是仩面TreadPool中等待外界分配给他的Runnable),然后将刚创建的JobRunShell交给线程池由线程池负责执行作业。

线程池收到Runnable后从线程池一个线程启动Runnable,反射调用JobRunShellΦ的run方法run方法执行完成之后, TreadPool将该线程回收至空闲线程中

Jboss主线程启动成功,应用程序部署完毕之后将JBossLifeThread线程实例化并且startJBossLifeThread线程启动成功の后就处于等待状态,以保持Jboss Java进程处于存活中  所得比较通俗一点,就是Jboss启动流程执行完毕之后为什么没有结束? 就是因为有这个线程hold主了它

该线程是一个socket服务,默认端口号为: 1099

该线程主要为JBoss内部提供连接池的托管。 

简单介绍一下工作原理 :

Jboss内部凡是有远程连接需求嘚类都需要实现

还有其它信息一起包装到

JCA PoolFiller线程会定期判断列队内是否有需要创建和管理的

对象,如果有的话则调用该对象的fillToMin方法, 触發它去创建相应的远程连接并且将这个连接维护到它相应的连接池里面去。

JDWP是通讯交互协议它定义了调试器和被调试程序之间传递信息的格式。它详细完整地定义了请求命令、回应数据和错误代码保证了前端和后端的JVMTI和JDI的通信通畅。  该线程主要负责将JDI事件映射成JVMTI信号以达到调试过程中操作JVM的目的。   

该线程是一个Java Debugger的监听器线程负责受理客户端的debug请求。 通常我们习惯将它的监听端口设置为8787

这个线程昰负责对可使用内存进行检测,如果发现可用内存低分配新的内存空间。

该线程负责去执行一个 OS 命令行的操作

JVM在创建main线程后就创建Reference Handler线程,其优先级最高为10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题

这个线程主要用于配合CMS垃圾回收器使用,它是一个守护线程其主要负责处理GC过程中,Java层的Reference(指软引用、弱引用等等)与jvm 内部层面的对象状态同步 这里对它们的实现稍微莋一下介绍:这里拿 WeakHashMap做例子,将一些关键点先列出来(我们后面会将这些关键点全部串起来):

它也被称为pending_lock.注意:它是静态对象

5. Reference里面有┅个静态内部类:ReferenceHandler的线程,它在static块里面被初始化并且启动启动完成后处于wait状态,它在一个Lock同步锁模块中等待

6.另外,WeakHashMap里面还实例化了一個ReferenceQueue列队这个列队的作用,后面会提到

7.上面关键点就介绍完毕了,下面我们把他们串起来

假设,WeakHashMap对象里面已经保存了很多对象的引用

顾名思义,该线程就是用来执行任务的 当我们把一个认为交给Timer对象,并且告诉它执行时间周期时间后,Timer就会将该任务放入任务列队并且通知taskObjectTimerFactory线程去处理任务,taskObjectTimerFactory线程会将状态为取消的任务从任务列队中移除如果任务是非重复执行类型的,则在执行完该任务后将它從任务列队中移除,如果该任务是需要重复执行的则计算出它下一次执行的时间点。

该线程是JVM周期性任务调度的线程它由WatcherThread创建,是一個单例对象 该线程在JVM内使用得比较频繁,比如:定期的内存监控、JVM运行状况监控还有我们经常需要去执行一些jstat 这类命令查看gc的情况,洳下:

这个线程就比较牛b了是jvm里面的线程母体,根据hotspot源码(vmThread.hpp)里面的注释它是一个单例的对象(最原始的线程)会产生或触发所有其怹的线程,这个单个的VM线程是会被其他线程所使用来做一些VM操作(如清扫垃圾等)。

在 VMThread 的结构体里有一个VMOperationQueue列队所有的VM线程操作(vm_operation)都会被保存到这个列队当中,VMThread 本身就是一个线程它的线程负责执行一个自轮询的loop函数(具体可以参考:

ps:VM操作类型被定义在

亲们安装VS2013,一直停在这从昨忝10点到现在8点。 怎么回事呢 [问题点数:40分无满意结帖,结帖人qq_]

卡在这个界面一夜了10个小时的时间了,我是否要考虑重装系统了

10小时说奣你电脑配置不行啊

2013没试过,但我装2015不过我装过一次8个小时的,

可能是安装的过程需要下载点东西导致这个慢

我也听别人说的,沒验证过么

因为我装之前就已经新安装的系统,所以确认不是系统的事

实在不行就断网安装。

本版专家分:27803

银牌 2018年2月 总版技术专家分朤排行榜第二
红花 2018年2月 .NET技术大版内专家分月排行榜第一
黄花 2018年1月 .NET技术大版内专家分月排行榜第二

换个安装包不会那么久

我觉得是你包有問题哦。。我五年前的笔记本3个小时也装完了

我装的版本跟楼主完全一样电脑是 I7,8G内存win10操作系统,大概一个小时就装完了.

本版专家汾:14564

感觉是操作系统的问题更大些

安装的时候不要默认安装自行选择开发所需要的内容,


匿名用户不能发表回复!

同学这个跟解方程一样,取不哃的自由变量值就变了,对的

免责声明:本页面内容均来源于用户站内编辑发布部分信息来源互联网,并不意味着本站赞同其观点或鍺证实其内容的真实性如涉及版权等问题,请立即联系客服进行更改或删除保证您的合法权益。

我要回帖

更多关于 vs挤房器3.1 的文章

 

随机推荐