jmeter线程组循环次数循环1亿次会报内存泄漏怎么解决

.Net下跟踪线程挂起和程序死循环
.Net 下的程序调试相对C/C++要简单很多,少了那些令人头疼的指针越界的问题。不过当你的程序遇 到如下问题时,依然非常棘手:
1. 进程异常终止。解决方案见 .Net 下未捕获异常的处理
2. 内存泄漏或者内存申请后程序始终没有释放。解决方案见 用 .NET Memory Profiler 跟踪.net 应 用内存使用情况--基本应用篇 。如果通过自己编写的程序监控,我将在以后的中阐述。
3. 线程因未知原因挂起,比如死锁。
4. 程序死循环。
本文将阐述如果编写程序对后两者故障实时跟踪并报告。
首先我们需要一个单独的监控线程来监控需要监控的线程
我做了一个监控类 ThreadMonitor,在开始监控之前,我们将监控线程的优先级设置为最高。
        public ThreadMonitor()
        {
            _MonitorThread = new Thread(new ThreadStart(MonitorTask));
            _MonitorThread.Priority = ThreadPriority.H
            _MonitorThread.IsBackground =
        }
接下来我们为这个线程提供几个公共方法
Start  方法让调用者启动监控
Register 方法用于将需要监控的线程注册到监控中
Heartbeat 方法后面说明
        /**//// &summary&
        /// Start monitor
        /// &/summary&
        public void Start()
        {
            _MonitorThread.Start();
        }
        /**//// &summary&
        /// Monitor register
        /// &/summary&
        /// &param name="monitorPara"&Monitor parameter&/param&
        public void Register(MonitorParameter monitorPara)
        {
            Debug.Assert(monitorPara != null);
            Debug.Assert(monitorPara.Thread != null);
             if (GetTCB(monitorPara.Thread) != null)
            {
                throw new System.ArgumentException("Register repeatedly!");
            }
            lock (_RegisterLock)
            {
                _TCBTable.Add(monitorPara.Thread.ManagedThreadId, new TCB (monitorPara));
            }
        }
        public void Heartbeat(Thread t)
        {
            TCB tcb = GetTCB(t);
            if (tcb == null)
            {
                throw new System.ArgumentException("This thread was not registered!");
            }
            tcb.LastHeartbeat = DateTime.N
            tcb.HitTimes = 0;
            tcb.Status &= ~ThreadStatus.H
        }C++内存泄漏的检查方法_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
C++内存泄漏的检查方法
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩1页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢判断内存性能表现主要是为了解决如下两个问题:
1. 当前web应用是否存在内存泄漏,如果有,问题的程度有多大?
2. 如果web应用的代码无法进一步改进,当前web应用所在的服务器是否存在内存上的瓶颈,是否需要增加内存数量来提高内存?
一、内存泄漏及判断
(一)、什么是内存泄漏?
程序都需要装载在内存中才能运行,退出的时候将内存返还给系统,有两种返还方式:
1. 自行返还: 程序员编写代码的时候返还,如C++代码。
2. 自动返还:&& 由支持程序运行的服务平台定期自动返还给系统,如Java、.Net等。
事实上,无论以上哪种方式,程序都有可能未把自己使用的内存返回给系统,从而导致之后的程序无法再使用这些内存,这些应该返还而没有返还的内存就像从管道漏掉了一样。
因为web程序都是持续不断的运行,如果代码存在内存泄漏的问题,泄漏的内存就会越来越多,越来越严重。导致系统可用的内存资源越来越少,系统性能越来越差,用户感受到的响应时间越来越慢。
(二)、性能计数器与内存泄漏
关注Process(进程)性能对象的如下几个计数器:
Handle Count(句柄数量): 进程的每个线程当前打开的句柄总数。
Thread Count(线程数量):线程的总数。
Virtual Bytes(虚拟内存字节数): 见后面关于虚拟内存的说明。
Working Set(工作集): 和当前进程有关的那一部分物理内存。
Private Byte(私有数据字节数): 此进程无法与其他进程共享的字节数量。
虚拟内存: 计算机内存有限,需要使用内存的程序非常多,大家都把需要的代码和数据全部放在内存中是吃不消的。所以操作系统在磁盘上也为程序开辟一块存储的地盘,当作内存使用,这就是虚拟内存。
可能存在内存泄漏的情况:
1. 一般来说:Virtual Bytes 应该远大于Working Set。如果:Virtual Bytes 增长较快,Working Set增长较少, 则可能存在内存泄漏的情况。
2. 以上所有性能计数器在测试期间数值持续增长,而测试停止后仍然维持在高水平,则可能存在内存泄漏。
(三)、使用工具软件测试代码是否存在内存泄漏情况
如JProbe套件、Rational Purify、Leakdiag、BoundsChecker和CLRProfiler等软件可以在代码不那么庞大的时候就进行单元测试、组件测试,不让问题积累起来。
阅读(...) 评论()Android中常见的内存泄漏汇总
集合类泄漏
集合类如果仅仅有添加元素的方法,而没有相应的删除机制,导致内存被占用。如果这个集合类是全局性的变量 (比如类中的静态属性,全局性的 map 等即有静态引用或 final 一直指向它),那么没有相应的删除机制,很可能导致集合所占用的内存只增不减。比如上面的典型例子就是其中一种情况,当然实际上我们在项目中肯定不会写这么 2B 的代码,但稍不注意还是很容易出现这种情况,比如我们都喜欢通过 HashMap 做一些缓存之类的事,这种情况就要多留一些心眼。
单例造成的内存泄漏
由于单例的静态特性使得其生命周期跟应用的生命周期一样长,所以如果使用不恰当的话,很容易造成内存泄漏。比如下面一个典型的例子,
public class AppManager {
private static AppM
private AppManager(Context context) {
this.context =
public static AppManager getInstance(Context context) {
if (instance == null) {
instance = new AppManager(context);
这是一个普通的单例模式,当创建这个单例的时候,由于需要传入一个Context,所以这个Context的生命周期的长短至关重要:
1、如果此时传入的是 Application 的 Context,因为 Application 的生命周期就是整个应用的生命周期,所以这将没有任何问题。
2、如果此时传入的是 Activity 的 Context,当这个 Context 所对应的 Activity 退出时,由于该 Context 的引用被单例对象所持有,其生命周期等于整个应用程序的生命周期,所以当前 Activity 退出时它的内存并不会被回收,这就造成泄漏了。
正确的方式应该改为下面这种方式:
public class AppManager {
private static AppM
private AppManager(Context context) {
this.context = context.getApplicationContext();// 使用Application 的context
public static AppManager getInstance(Context context) {
if (instance == null) {
instance = new AppManager(context);
或者这样写,连 Context 都不用传进来了:
在你的 Application 中添加一个静态方法,getContext() 返回 Application 的 context,
context = getApplicationContext();
* 获取全局的context
* @return 返回全局context对象
public static Context getContext(){
public class AppManager {
private static AppM
private AppManager() {
this.context = MyApplication.getContext();// 使用Application 的context
public static AppManager getInstance() {
if (instance == null) {
instance = new AppManager();
匿名内部类/非静态内部类和异步线程
非静态内部类创建静态实例造成的内存泄漏
有的时候我们可能会在启动频繁的Activity中,为了避免重复创建相同的数据资源,可能会出现这种写法:
public class MainActivity extends AppCompatActivity {
private static TestResource mResource =
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(mManager == null){
mManager = new TestResource();
class TestResource {
这样就在Activity内部创建了一个非静态内部类的单例,每次启动Activity时都会使用该单例的数据,这样虽然避免了资源的重复创建,不过这种写法却会造成内存泄漏,因为非静态内部类默认会持有外部类的引用,而该非静态内部类又创建了一个静态的实例,该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。正确的做法为:
将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,请按照上面推荐的使用Application 的 Context。当然,Application 的 context 不是万能的,所以也不能随便乱用,对于有些地方则必须使用 Activity 的 Context,对于Application,Service,Activity三者的Context的应用场景如下:
其中: NO1表示 Application 和 Service 可以启动一个 Activity,不过需要创建一个新的 task 任务队列。而对于 Dialog 而言,只有在 Activity 中才能创建
匿名内部类
android开发经常会继承实现Activity/Fragment/View,此时如果你使用了匿名类,并被异步线程持有了,那要小心了,如果没有任何措施这样一定会导致泄露
public class MainActivity extends Activity {
Runnable ref1 = new MyRunable();
Runnable ref2 = new Runnable() {
public void run() {
ref1和ref2的区别是,ref2使用了匿名内部类。我们来看看运行时这两个引用的内存:
可以看到,ref1没什么特别的。
但ref2这个匿名类的实现对象里面多了一个引用:
this$0这个引用指向MainActivity.this,也就是说当前的MainActivity实例会被ref2持有,如果将这个引用再传入一个异步线程,此线程和此Acitivity生命周期不一致的时候,就造成了Activity的泄露。
造成的内存泄漏
Handler 的使用造成的内存泄漏问题应该说是最为常见了,很多时候我们为了避免 ANR 而不在主线程进行耗时操作,在处理网络任务或者封装一些请求回调等api都借助Handler来处理,但 Handler 不是万能的,对于 Handler 的使用代码编写一不规范即有可能造成内存泄漏。另外,我们知道 Handler、Message 和 MessageQueue 都是相互关联在一起的,万一 Handler 发送的 Message 尚未被处理,则该 Message 及发送它的 Handler 对象将被线程 MessageQueue
一直持有。
由于 Handler 属于 TLS(Thread Local Storage) 变量, 生命周期和 Activity 是不一致的。因此这种实现方式一般很难保证跟 View 或者 Activity 的生命周期保持一致,故很容易导致无法正确释放。
举个例子:
public class SampleActivity extends Activity {
private final Handler mLeakyHandler = new Handler() {
public void handleMessage(Message msg) {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Post a message and delay its execution for 10 minutes.
mLeakyHandler.postDelayed(new Runnable() {
public void run() { /* ... */ }
}, 1000 * 60 * 10);
// Go back to the previous Activity.
在该 SampleActivity 中声明了一个延迟10分钟执行的消息 Message,mLeakyHandler 将其 push 进了消息队列 MessageQueue 里。当该 Activity 被 finish() 掉时,延迟执行任务的 Message 还会继续存在于主线程中,它持有该 Activity 的 Handler 引用,所以此时 finish() 掉的 Activity 就不会被回收了从而造成内存泄漏(因 Handler 为非静态内部类,它会持有外部类的引用,在这里就是指 SampleActivity)。
修复方法:在 Activity 中避免使用非静态内部类,比如上面我们将 Handler 声明为静态的,则其存活期跟 Activity 的生命周期就无关了。同时通过弱引用的方式引入 Activity,避免直接将 Activity 作为 context 传进去,见下面代码:
public class SampleActivity extends Activity {
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
private static class MyHandler extends Handler {
private final WeakReference&SampleActivity& mA
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference&SampleActivity&(activity);
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
private final MyHandler mHandler = new MyHandler(this);
* Instances of anonymous classes do not hold an implicit
* reference to their outer class when they are &static&.
private static final Runnable sRunnable = new Runnable() {
public void run() { /* ... */ }
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Post a message and delay its execution for 10 minutes.
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
// Go back to the previous Activity.
综述,即推荐使用静态内部类 + WeakReference 这种方式。每次使用前注意判空。
前面提到了 WeakReference,所以这里就简单的说一下 Java 对象的几种引用类型。
Java对引用的分类有 Strong reference, SoftReference, WeakReference, PhatomReference 四种。
在Android应用的开发中,为了防止内存溢出,在处理一些占用内存大而且声明周期较长的对象时候,可以尽量应用软引用和弱引用技术。
软/弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。利用这个队列可以得知被回收的软/弱引用的对象列表,从而为缓冲器清除已失效的软/弱引用。
假设我们的应用会用到大量的默认图片,比如应用中有默认的头像,默认游戏图标等等,这些图片很多地方会用到。如果每次都去读取图片,由于读取文件需要硬件操作,速度较慢,会导致性能较低。所以我们考虑将图片缓存起来,需要的时候直接从内存中读取。但是,由于图片占用内存空间比较大,缓存很多图片需要很多的内存,就可能比较容易发生OutOfMemory异常。这时,我们可以考虑使用软/弱引用技术来避免这个问题发生。以下就是高速缓冲器的雏形:
首先定义一个HashMap,保存软引用对象。
private Map &String, SoftReference&Bitmap&& imageCache = new HashMap &String, SoftReference&Bitmap&& ();
再来定义一个方法,保存Bitmap的软引用到HashMap。
使用软引用以后,在OutOfMemory异常发生之前,这些缓存的图片资源的内存空间可以被释放掉的,从而避免内存达到上限,避免Crash发生。
如果只是想避免OutOfMemory异常的发生,则可以使用软引用。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。
另外可以根据对象是否经常使用来判断选择软引用还是弱引用。如果该对象可能会经常使用的,就尽量用软引用。如果该对象不被使用的可能性更大些,就可以用弱引用。
ok,继续回到主题。前面所说的,创建一个静态Handler内部类,然后对 Handler 持有的对象使用弱引用,这样在回收时也可以回收 Handler 持有的对象,但是这样做虽然避免了 Activity 泄漏,不过 Looper 线程的消息队列中还是可能会有待处理的消息,所以我们在 Activity 的 Destroy 时或者 Stop 时应该移除消息队列 MessageQueue 中的消息。
下面几个方法都可以移除 Message:
public final void removeCallbacks(Runnable r);
public final void removeCallbacks(Runnable r, Object token);
public final void removeCallbacksAndMessages(Object token);
public final void removeMessages(int what);
public final void removeMessages(int what, Object object);
尽量避免使用
static 成员变量
如果成员变量被声明为 static,那我们都知道其生命周期将与整个app进程生命周期一样。
这会导致一系列问题,如果你的app进程设计上是长驻内存的,那即使app切到后台,这部分内存也不会被释放。按照现在手机app内存管理机制,占内存较大的后台进程将优先回收,yi'wei如果此app做过进程互保保活,那会造成app在后台频繁重启。当手机安装了你参与开发的app以后一夜时间手机被消耗空了电量、流量,你的app不得不被用户卸载或者静默。
这里修复的方法是:
不要在类初始时初始化静态成员。可以考虑lazy初始化。 架构设计上要思考是否真的有必要这样做,尽量避免。如果架构需要这么设计,那么此对象的生命周期你有责任管理起来。
override finalize()
1、finalize 方法被执行的时间不确定,不能依赖与它来释放紧缺的资源。时间不确定的原因是: 虚拟机调用GC的时间不确定 Finalize daemon线程被调度到的时间不确定
2、finalize 方法只会被执行一次,即使对象被复活,如果已经执行过了 finalize 方法,再次被 GC 时也不会再执行了,原因是:
含有 finalize 方法的 object 是在 new 的时候由虚拟机生成了一个 finalize reference 在来引用到该Object的,而在 finalize 方法执行的时候,该 object 所对应的 finalize Reference 会被释放掉,即使在这个时候把该 object 复活(即用强引用引用住该 object ),再第二次被 GC 的时候由于没有了 finalize reference 与之对应,所以 finalize 方法不会再执行。
3、含有Finalize方法的object需要至少经过两轮GC才有可能被释放。
资源未关闭造成的内存泄漏
对于使用了BraodcastReceiver,ContentObserver,File,游标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。
一些不良代码造成的内存压力
有些代码并不造成内存泄露,但是它们,或是对没使用的内存没进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存。
比如: Bitmap 没调用 recycle()方法,对于 Bitmap 对象在不使用时,我们应该先调用 recycle() 释放内存,然后才它设置为 null. 因为加载 Bitmap 对象的内存空间,一部分是 java 的,一部分 C 的(因为 Bitmap 分配的底层是通过 JNI 调用的 )。 而这个 recyle() 就是针对 C 部分的内存释放。 构造 Adapter 时,没有使用缓存的 convertView ,每次都在创建新的 converView。这里推荐使用 ViewHolder。
对 Activity 等组件的引用应该控制在 Activity 的生命周期之内; 如果不能就考虑使用 getApplicationContext 或者 getApplication,以避免 Activity 被外部长生命周期的对象引用而泄露。
尽量不要在静态变量或者静态内部类中使用非静态外部成员变量(包括context ),即使要使用,也要考虑适时把外部成员变量置空;也可以在内部类中使用弱引用来引用外部类的变量。
对于生命周期比Activity长的内部类对象,并且内部类中使用了外部类的成员变量,可以这样做避免内存泄漏:
将内部类改为静态内部类
静态内部类中使用弱引用来引用外部类的成员变量
Handler 的持有的引用对象最好使用弱引用,资源释放时也可以清空 Handler 里面的消息。比如在 Activity onStop 或者 onDestroy 的时候,取消掉该 Handler 对象的 Message和 Runnable.
在 Java 的实现过程中,也要考虑其对象释放,最好的方法是在不使用某对象时,显式地将此对象赋值为 null,比如使用完Bitmap 后先调用 recycle(),再赋为null,清空对图片等资源有直接引用或者间接引用的数组(使用 array.clear() ; array = null)等,最好遵循谁创建谁释放的原则。
正确关闭资源,对于使用了BraodcastReceiver,ContentObserver,File,游标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销。
保持对对象生命周期的敏感,特别注意单例、静态对象、全局性集合等的生命周期。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:31231次
排名:千里之外
原创:24篇
转载:18篇
(2)(1)(2)(1)(1)(5)(5)(7)(2)(1)(2)(1)(1)(1)(1)(1)(9)> Java 多线程或内存泄漏缺陷排查的一些经验
Java 多线程或内存泄漏缺陷排查的一些经验
相关推荐:
在用visual studio进行界面编程时(如MFC),前台UI我们可以通过MFC的消息循环机制实现。而对于后台的数据处理,我们可能会用到多线程来处理。那么对于大多数人(尤其是我这种菜鸟),一个比较快捷的方法便是选择MFC多线程:AfxBeginThread或者CreateThr
Java 多线程或内存泄漏缺陷排查的一些经验 JVM Thread DUMP 基本功 Windows 下用Ctrl-Break,Unix 下用 kill -3 &pid& 的命令让JVM输出 thread dump。 每隔几秒 thread dump 一次,多做几次,分析比较。 Thread Dump分析的一些经验 1 找出这几次Thread dump 文件中,有哪些 Java Thread 处于长时间等待状态,很有可能就是问题之所在。 2 如果Java 线程等在某些不可能出错的地方,如 java.lang.XXX/java.util.XXX对象的某个方法,则很有可能是因为出现了 OutOfMemoryError 异常,原因不外乎是JVM 堆内存过小或出现内存泄漏。 3 对于死锁,最直接的表现就是至少两个线程长时间等待相互持有的对象(每个线程所持有的对象和它当前等待的对象都可以从 dump 中看到)。 4 对于死循环,要辅助CPU占用率确定;如果发现CPU至少一颗使用率为100%,并且有线程长时间位于用户代码处,则很有可能是死循环引起。 多线程缺陷排查 对于Java死锁问题很少出现,多线程访问变量时冲突很常见。 一般出在多线程共享同一对象实例如全局Map,Servlet,Interceptor,或如多线程同时访问某个静态方法,而此静态方法不巧又访问另一个静态变量。 这类问题自测发现不了,在并发压力测试时才能发现。如果代码的入口检查做得好,多半会抛出一些莫名其妙的异常;要不然就会出现正常运行但数据库记录不对的情况。 对这种问题,并无多好的办法解决,主要还是靠看异常堆栈和静态代码分析来解决。 内存泄漏排查 一般用商用辅助工具排查,但有可能出现在JVM heap dump 模式下,运行极度缓慢的情况。 笨笨曾经用过一个非常简单的工具,效果不错,它可以做到在不影响jvm 执行速度的情况下,做heap dump,然后对dump出的文件进行排序,检查即可。 heapprofile(http://www.virtualmachine.de/) thread dump的结果太长了, 如何能让thread dump的结果输出在文件中? 要分 JDK . IBM JDK 始终输出 Thread Dump到某个文件中。 Sun/Jrockit JDK 会输出到 stdout 中。 对于 Sun/JRockit JDK,最简单的办法 是重定向 stdout 到某个文件: java xxx.jar & xxx.txt 最复杂的办法是用 JNI 实时修改 STDOUT/STDERR handler。 第一次翻译,大家凑合着看,英文好的请看原文:/~moazam/stories//debuggingHangsInTheJvm.html 在JVM挂起时调试线程 有时,JAVA用户或开发者会遇到JAVA应用程序看起来像挂起的问题,而且没有核心文件产生,没有任何的IO检测,这个过程只是坐在那里等待...通常这些问题可以追溯到操作系统和的JVM级别线程。 以下内容是从Solaris方面来介绍的,也许不久我会写些针对Linux线程的东西 两个线程模型的故事 Solaris 8和9有两个独立的线程模型。在sun的官方网站上有一个权威的解释 。点这里进入。我这边基本上长话短说, Solaris 8下,默认情况下,使用一个多对多线程模型,而Solaris 9采用了一对一线程模型。 在Solaris 9发布以后, Solaris 8还包括一对一线程模型作为'替代'的线程模型。用户如果想在Solaris 8使用“替代”的线程库,应当确保他们运行过最新的108993修补程序,早些时候反映此线程库有漏洞,后来采用上述补丁来修正。该线程模型的库是在/usr/lib/lwp下 。 当JAVA进程挂起时,你应该怎么做 在你的Java程序挂起时,有几个不同的事情, 您可以尝试。 1.得到一个Java级别的堆栈跟踪。 2.获取当前LWPs(light weight process)和它们当前状态的快照 3.获得底层原生级别堆栈跟踪。 4.尝试对进程抛出SIGWAITING信号 5.强制进程dump一个core文件 6.切换到替代线程库,然后试着重现那个问题 下面更详细地说明每一个步骤.. 1.得到一个Java级别堆栈跟踪。 这里的目的是从挂起进程中获得一个Java级别的堆栈跟踪。Java级别堆栈跟踪看起来如下所示: 可以从几个不同方式来介绍Java级别的堆栈跟踪。在UNIX环境中,您可以发送的进程SIGQUIT信号(kill -3 ,或kill -SIGQUIT ),然后进程将打印堆栈跟踪到控制台。在Windows中,你只能在启动这一进程的控制台按下Ctrl - \。 如果您已使用用-Xrs参数来启动JVM,发送SIGQUIT和SIGWAITING信号将无效 。-Xrs参数的目的是告诉JVM忽视系统的信号。 为了记录进程的堆栈跟踪信息,您可以在启动JAVA程序时就重定向stdout和stderr到一个文件。 例如,要把jEdit程序的stderr和stdout重定向到一个叫&console.txt'的文件中,我们可以这样做: java -jar jedit.jar & console.txt 2&&1 这个方法在Unix和Windows都适合 。 如果只是想stdout 的线程堆栈在 txt中打印就向下面打印的: 运行中的窗口中 使用ctrl + break 就可以将线程信息打印在文本中 java -jar jedit.jar & console.txt 即可 2.获取当前LWPs(light weight process)和它们当前状态的快照 本节旨在针对Solaris用户。很多人使用'top'或'prstat'来查看每个进程消耗了多少CPU,内存等。'prstat'命令允许用户查看在LWP级别,粒度更细的资源状况。只需运行'prstat -L'即可 prstat输出看起来像这样: 从上面的输出,您可以看到,有一个Java的过程,但它有多个LWPs在运行。前两个( 13和10 )正消耗了6.1%和1.9%的CPU 。现在,当你接着往下看第三点的底层原生级别的堆栈跟踪,你将会明确知道某一个LWP正在做些什么 3.获得底层原生级别堆栈跟踪。 Solaris有一个非常有用的命令叫做'pstack' 。Linux用户也有福, 罗斯汤普森高人已经移植这个命令到Linux,你可以从这里下载 。 pstack命令能够根据指定的PID返回进程的调用过程。它显示了LWP的编号以及在pstack命令运行时的那时刻的系统调用信息。这对于检查为什么一个进程挂起或崩溃是有很大的帮助。 以下是底层原生堆栈跟踪,对应于上面的JAVA级别的堆栈跟踪。Java级别的跟踪显示了0x22n的nid,对应十六进制是34 。我可以从上面的Java级别堆栈跟踪输出的前两行可以看出来。 &SideKick #1& prio=1 tid=0x00593b80 nid=0x22 因此,我们将在pstack输出内容中寻找LWP为34的。您可能还注意到,在'prstat -L'的输出中的第6行,里面的LWP也是LWP 34, 而它当前消耗了0.3%的CPU。 4.尝试对进程抛出SIGWAITING信号。 SIGWAITING游戏 第一件事是我建议大家在JAVA程序挂起时,尝试发送一个SIGWAITING信号给它。这是Solaris 8要求的,但你在Solaris 9下不需要这样做,因为它有一个不同的默认线程的行为。什么是SIGWAITING ?它是信号32,且它的定义是: &A signal that is implemented in Solaris and used to tell a threaded process that it should consider creating a new LWP.& 通常,当一个发生挂起时,一个LWP中有多个线程在调度,其中的一个被阻塞,而其他的可能仍然在运行。其他正在运行的线程可能就会变成孤魂野鬼,因为没有LWP可以依附。当SIGWAITING信号发送到挂起进程时,线程库将建立一个新的LWP,并重新调度那些“其他正在运行“的线程。可能会把原来挂起的进程救活。 5.强制一个进程dump一个core文件 如果上面所有的方法都不行的话,你也许需要在堆栈跟踪中进行更深层次的分析。而一个core文件将会指出哪些是导致进程挂起的。当一个进程处在挂起状态时,它不会自动dump出core文件。在Solaris上有一个名为'gcore'的命令,它能够强制一个处在任何状态的进程dump出core文件。使用简单, gcore &pid& 。 请确认您已在Solaris使用coreadm或ulimit命令开启core dump功能。 例如,想把使用全局唯一命名的core文件保存到/var/core/目录下,切换到root用户并使用下面命令: mkdir -p /var/cores coreadm -g /var/cores/%f.%n.%p.core -e global -e process -e global-setid -e proc-setid -e log 我个人认为,Java级别的堆栈跟踪,pstack的底层原生的堆栈跟踪,及prstat -L的输出数据已经足够了。因此core文件并不一定需要。 6.切换到替换线程库,并尝试重现该问题。 如果SIGWAITING信号确实帮助挂起的进程重新活过来,那么你运气不错。此时你应该切换到替换线程库,看看是否会重新出现挂起现象。一般来说,它不会再发生。 把你的应用程序切换到替换线程库是比较简单的,不需要重新编译。只需重置LD_LIBRARY_PATH环境变量以指向新的线程库。例如: LD_LIBRARY_PATH = / usr / lib中/ lwp LD_LIBRARY_PATH_64 = / usr/lib/lwp/64 You can find much more details about the alternate thread library and how to use it by reading this article, Alternate Thread Library (T2) -- New in the Solaris 8 Operating Environment
Java 多线程或内存泄漏缺陷排查的一些经验 JVM Thread DUMP 基本功 Windows 下用Ctrl-Break,Unix 下用 kill -3 &pid& 的命令让JVM输出 thread dump。 每隔几秒 thread dump 一次,多做几次,分
------分隔线----------------------------
相关阅读排行
相关最新文章
Copyright 2012- ( Coin163 ) All Rights Reserved &&

我要回帖

更多关于 java 线程 内存泄漏 的文章

 

随机推荐