服务器如何打印堆栈的数据
❶ 如何在进程崩溃后打印堆栈并防止数据丢失
进程在运行过程中遇到逻辑错误, 比如除零, 空指针等等, 系统会触发一个软件中断.
这个中断会以信号的方式通知进程, 这些信号的默认处理方式是结束进程.
发生这种情况, 我们就认为进程崩溃了.
进程崩溃后, 我们会希望知道它是为何崩溃的, 是哪个函数, 哪行代码引起的错误.
另外, 在进程退出前, 我们还希望做一些善后处理, 比如把某些数据存入数据库, 等等.
下面, 我会介绍一些技术来达成这两个目标.
1. 在core文件中查看堆栈信息
如果进程崩溃时, 我们能看到当时的堆栈信息, 就能很快定位到错误的代码.
在 gcc 中加入 -g 选项, 可执行文件中便会包含调试信息. 进程崩溃后, 会生成一个 core 文件.
我们可以用 gdb 查看这个 core 文件, 从而知道进程崩溃时的环境.
在调试阶段, core文件能给我们带来很多便利. 但是在正式环境中, 它有很大的局限:
1. 包含调试信息的可执行文件会很大. 并且运行速度也会大幅降低.
2. 一个 core 文件常常很大, 如果进程频繁崩溃, 硬盘资源会变得很紧张.
所以, 在正式环境中运行的程序, 不会包含调试信息.
它的core文件的大小, 我们会把它设为0, 也就是不会输入core文件.
在这个前提下, 我们如何得到进程的堆栈信息呢?
2. 动态获取线程的堆栈
c 语言提供了 backtrace 函数, 通过这个函数可以动态的获取当前线程的堆栈.
要使用 backtrace 函数, 有两点要求:
1. 程序使用的是 ELF 二进制格式.
2. 程序连接时使用了 -rdynamic 选项.
-rdynamic可用来通知链接器将所有符号添加到动态符号表中, 这些信息比 -g 选项的信息要少得多.
下面是将要用到的函数说明:
#include <execinfo.h>
int backtrace(void **buffer,int size);
用于获取当前线程的调用堆栈, 获取的信息将会被存放在buffer中, 它是一个指针列表。
参数 size 用来指定buffer中可以保存多少个void* 元素。
函数返回值是实际获取的指针个数, 最大不超过size大小
注意: 某些编译器的优化选项对获取正确的调用堆栈有干扰,
另外内联函数没有堆栈框架; 删除框架指针也会导致无法正确解析堆栈内容;
char ** backtrace_symbols (void *const *buffer, int size)
把从backtrace函数获取的信息转化为一个字符串数组.
参数buffer应该是从backtrace函数获取的指针数组,
size是该数组中的元素个数(backtrace的返回值) ;
函数返回值是一个指向字符串数组的指针, 它的大小同buffer相同.
每个字符串包含了一个相对于buffer中对应元素的可打印信息.
它包括函数名,函数的偏移地址, 和实际的返回地址.
该函数的返回值是通过malloc函数申请的空间, 因此调用者必须使用free函数来释放指针.
注意: 如果不能为字符串获取足够的空间, 函数的返回值将会为NULL.
void backtrace_symbols_fd (void *const *buffer, int size, int fd)
与backtrace_symbols 函数具有相同的功能,
不同的是它不会给调用者返回字符串数组, 而是将结果写入文件描述符为fd的文件中,每个函数对应一行.
3. 捕捉信号
我们希望在进程崩溃时打印堆栈, 所以我们需要捕捉到相应的信号. 方法很简单.
#include <signal.h>
void (*signal(int signum,void(* handler)(int)))(int);
或者: typedef void(*sig_t) ( int );
sig_t signal(int signum,sig_t handler);
参数说明:
第一个参数signum指明了所要处理的信号类型,它可以是除了SIGKILL和SIGSTOP外的任何一种信号。
第二个参数handler描述了与信号关联的动作,它可以取以下三种值:
1. 一个返回值为正数的函数的地址, 也就是我们的信号处理函数.
这个函数应有如下形式的定义: int func(int sig); sig是传递给它的唯一参数。
执行了signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行func()函数。
当func()函数执行结束后,控制权返回进程被中断的那一点继续执行。
2. SIGIGN, 忽略该信号.
3. SIGDFL, 恢复系统对信号的默认处理。
返回值: 返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。
注意:
当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,
直到信号处理函数执行完毕再重新调用相应的处理函数。
如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。
在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预设的处理方式,
如果要改变此操作请改用sigaction()。
4. 实例
下面我们实际编码, 看看具体如何在捕捉到信号后, 打印进程堆栈, 然后结束进程.
#include <iostream>
#include <time.h>
#include <signal.h>
#include <string.h>
#include <execinfo.h>
#include <fcntl.h>
#include <map>
using namespace std;
map<int, string> SIG_LIST;
#define SET_SIG(sig) SIG_LIST[sig] = #sig;
void SetSigList(){
SIG_LIST.clear();
SET_SIG(SIGILL)//非法指令
SET_SIG(SIGBUS)//总线错误
SET_SIG(SIGFPE)//浮点异常
SET_SIG(SIGABRT)//来自abort函数的终止信号
SET_SIG(SIGSEGV)//无效的存储器引用(段错误)
SET_SIG(SIGPIPE)//向一个没有读用户的管道做写操作
SET_SIG(SIGTERM)//软件终止信号
SET_SIG(SIGSTKFLT)//协处理器上的栈故障
SET_SIG(SIGXFSZ)//文件大小超出限制
SET_SIG(SIGTRAP)//跟踪陷阱
}
string& GetSigName(int sig){
return SIG_LIST[sig];
}
void SaveBackTrace(int sig){
//打开文件
time_t tSetTime;
time(&tSetTime);
tm* ptm = localtime(&tSetTime);
char fname[256] = {0};
sprintf(fname, "core.%d-%d-%d_%d_%d_%d",
ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
FILE* f = fopen(fname, "a");
if (f == NULL){
exit(1);
}
int fd = fileno(f);
//锁定文件
flock fl;
fl.l_type = F_WRLCK;
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
fl.l_pid = getpid();
fcntl(fd, F_SETLKW, &fl);
//输出程序的绝对路径
char buffer[4096];
memset(buffer, 0, sizeof(buffer));
int count = readlink("/proc/self/exe", buffer, sizeof(buffer));
if(count > 0){
buffer[count] = '\n';
buffer[count + 1] = 0;
fwrite(buffer, 1, count+1, f);
}
//输出信息的时间
memset(buffer, 0, sizeof(buffer));
sprintf(buffer, "Dump Time: %d-%d-%d %d:%d:%d\n",
ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday,
ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
fwrite(buffer, 1, strlen(buffer), f);
//线程和信号
sprintf(buffer, "Curr thread: %d, Catch signal:%s\n",
pthread_self(), GetSigName(sig).c_str());
fwrite(buffer, 1, strlen(buffer), f);
//堆栈
void* DumpArray[256];
int nSize = backtrace(DumpArray, 256);
sprintf(buffer, "backtrace rank = %d\n", nSize);
fwrite(buffer, 1, strlen(buffer), f);
if (nSize > 0){
char** symbols = backtrace_symbols(DumpArray, nSize);
if (symbols != NULL){
for (int i=0; i<nSize; i++){
fwrite(symbols[i], 1, strlen(symbols[i]), f);
fwrite("\n", 1, 1, f);
}
free(symbols);
}
}
//文件解锁后关闭, 最后终止进程
fl.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &fl);
fclose(f);
exit(1);
}
void SetSigCatchFun(){
map<int, string>::iterator it;
for (it=SIG_LIST.begin(); it!=SIG_LIST.end(); it++){
signal(it->first, SaveBackTrace);
}
}
void Fun(){
int a = 0;
int b = 1 / a;
}
static void* ThreadFun(void* arg){
Fun();
return NULL;
}
int main(){
SetSigList();
SetSigCatchFun();
printf("main thread id = %d\n", (pthread_t)pthread_self());
pthread_t pid;
if (pthread_create(&pid, NULL, ThreadFun, NULL)){
exit(1);
}
printf("fun thread id = %d\n", pid);
for(;;){
sleep(1);
}
return 0;
}
文件名为 bt.cpp
编译: g++ bt.cpp -rdynamic -I /usr/local/include -L /usr/local/lib -pthread -o bt
主线程创建了 fun 线程, fun 线程有一个除零错误, 系统抛出 SIGFPE 信号.
该信号使 fun 线程中断, 我们注册的 SaveBackTrace 函数捕获到这个信号, 打印相关信息, 然后终止进程.
在输出的core文件中, 我们可以看到简单的堆栈信息.
5. 善后处理
在上面的例子中, fun 线程被 SIGFPE 中断, 转而执行 SaveBackTrace 函数.
此时, main 线程仍然在正常运行.
如果我们把 SaveBackTrace 函数最后的 exit(1); 替换成 for(;;)sleep(1);
main 线程就可以一直正常的运行下去.
利用这个特点, 我们可以做很多其它事情.
游戏的服务器进程常常有这些线程:
网络线程, 数据库线程, 业务处理线程. 引发逻辑错误的代码常常位于业务处理线程.
而数据库线程由于功能稳定, 逻辑简单, 是十分强壮的.
那么, 如果业务处理线程有逻辑错误, 我们捕捉到信号后, 可以在信号处理函数的最后,
通知数据库线程保存游戏数据.
直到数据库线程把游戏信息全部存入数据库, 信号处理函数才返回.
这样, 服务器宕机不会导致回档, 损失被大大降低.
要实现这个机制, 要求数据库模块和业务处理模块具有低耦合度.
当然, 实际应用的时候, 还有许多细节要考虑.
比如, 业务处理线程正在处理玩家的数据, 由于发生不可预知的错误, 玩家的数据被损坏了, 这些玩家的数据就不应该被存入数据库.
❷ 如何用Jstack把java进程中的堆栈信息输出到
1.2 Thread Dump特点
1. 能在各种操作系统下使用
2. 能在各种Java应用服务器下使用
3. 可以在生产环境下使用而不影响系统的性能
4. 可以将问题直接定位到应用程序的代码行上
1.3 Thread Dump 能诊断的问题
1. 查找内存泄露,常见的是程序里load大量的数据到缓存;
2. 发现死锁线程;
1.4如何抓取Thread Dump
一般当服务器挂起,崩溃或者性能底下时,就需要抓取服务器的线程堆栈(Thread Dump)用于后续的分析. 在实际运行中,往往一次 mp的信息,还不足以确认问题。为了反映线程状态的动态变化,需要接连多次做threadmp,每次间隔10-20s,建议至少产生三次 mp信息,如果每次 mp都指向同一个问题,我们才确定问题的典型性。
有很多方式可用于获取ThreadDump, 下面列出一部分获取方式:
操作系统命令获取ThreadDump:
Windows:
1.转向服务器的标准输出窗口并按下Control + Break组合键, 之后需要将线程堆栈复制到文件中;
UNIX/ linux:
首先查找到服务器的进程号(process id), 然后获取线程堆栈.
1. ps –ef | grep java
2. kill -3 <pid>
注意:一定要谨慎, 一步不慎就可能让服务器进程被杀死。kill -9 命令会杀死进程。
❸ c语言如何将函数调用堆栈打印出来
可以直接用输出在函数内部调用时,把调用顺序打印出来。
一、一个由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。-程序结束后有系统释放
4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
二、例程:
//main.cpp
inta=0;全局初始化区
char*p1;全局未初始化区
main()
{
intb;栈
chars[]="abc";栈
char*p2;栈
char*p3="123456";123456在常量区,p3在栈上。
staticintc=0;全局(静态)初始化区
p1=(char*)malloc(10);
p2=(char*)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1,"123456");123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
❹ 如何通过网络打印机打印阿里云服务器里面的数据
第一种:
1、将服务器上的文件通过邮件、qq等方式发到本地电脑上后直接打印。
2、连接服务器选择高级/显示选项->本地资源->本地设备和资源->选中打印机
或者将本机架设成服务器用远程服务器连接本机服务器打印这个比较麻烦建议采第一种的1和2
第二种:如果远程服务器与本地电脑同在一个局域网,可以在远程服务器上安装网络打印机,然后在远程服务器上直接打印。
安装网络打印机的步骤:在远程服务器上打开控制面板,找到 添加设备和打印,选择 添加网络打印机,然后输入本机(连接打印机的电脑)的IP地址进行搜索。搜索到之后选中打印机,点击安装,会在远程打印机上安装驱动程序,驱动程序安装完毕就可以使用网络打印机了
❺ kill-3生成的线程堆栈怎么查看
第一步:在终端运行Java程序
第二步:通过命令 pidof java 找到已经启动的java进程的ID,选择需要查看的java程序的进程ID
第三步:使用命令 kill -3 <java进行的 pid> 打印出java程序的线程堆栈信息
第四步:通常情况下运行的项目可和卖迅能会比较大,那么这个时候打印的堆栈信息可能会有几千到几万行,为了方便查看,我们往往需要将输出内容进行重定向
使用linux下的重定向命令方式即可:例如: demo.sh > run.log 2>&1 将输出信息重定向到 run.log中。
注:在操作系统中,0 1 2分别对应着不同的含义, 如下:
0 : 标准输入,即:C中的stdin , java中的System.in
1 : 标准输出, 即:C中的stdout ,java中的配正System.out
2 : 错误输出, 即:C中的stderr , java中的System.err
Demo:
----------------------------------------------------------------------------------------------
Sources Code :
public class PrintThreadTrace {
Object obj1 = new Object();
Object obj2 = new Object();
public void func1(){
synchronized (obj1){
func2();
}
}
public void func2(){
synchronized (obj2){
while(true){
System.out.print("");
}
}
}
public static void main(String[] args){
PrintThreadTrace ptt = new PrintThreadTrace();
ptt.func1();
}
}
----------------------------------------------------------------------------------------------------------------
按照步骤操作后唤此的打印输出信息:
Full thread mp Java HotSpot(TM) 64-Bit Server VM (24.79-b02 mixed mode):
"Service Thread" daemon prio=10 tid=0x00007fdc880a9000 nid=0x12a4 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" daemon prio=10 tid=0x00007fdc880a7000 nid=0x12a3 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" daemon prio=10 tid=0x00007fdc880a4000 nid=0x12a2 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Command Reader" daemon prio=10 tid=0x00007fdc50001000 nid=0x1299 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Event Helper Thread" daemon prio=10 tid=0x00007fdc880a1800 nid=0x1298 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Transport Listener: dt_socket" daemon prio=10 tid=0x00007fdc8809e000 nid=0x1297 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=10 tid=0x00007fdc88091000 nid=0x1296 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=10 tid=0x00007fdc88071800 nid=0x1295 in Object.wait() [0x00007fdc77ffe000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000ecb04858> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x00000000ecb04858> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" daemon prio=10 tid=0x00007fdc8806f800 nid=0x1294 in Object.wait() [0x00007fdc7c10b000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000ecb04470> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
- locked <0x00000000ecb04470> (a java.lang.ref.Reference$Lock)
"main" prio=10 tid=0x00007fdc8800b800 nid=0x128e runnable [0x00007fdc8fef7000]
java.lang.Thread.State: RUNNABLE
at com.wenchain.study.PrintThreadTrace.func2(PrintThreadTrace.java:20)
- locked <0x00000000ecc04b20> (a java.lang.Object)
at com.wenchain.study.PrintThreadTrace.func1(PrintThreadTrace.java:13)
- locked <0x00000000ecc04b10> (a java.lang.Object)
at com.wenchain.study.PrintThreadTrace.main(PrintThreadTrace.java:27)
"VM Thread" prio=10 tid=0x00007fdc8806b000 nid=0x1293 runnable
"GC task thread#0 (ParallelGC)" prio=10 tid=0x00007fdc88021000 nid=0x128f runnable
"GC task thread#1 (ParallelGC)" prio=10 tid=0x00007fdc88023000 nid=0x1290 runnable
"GC task thread#2 (ParallelGC)" prio=10 tid=0x00007fdc88024800 nid=0x1291 runnable
"GC task thread#3 (ParallelGC)" prio=10 tid=0x00007fdc88026800 nid=0x1292 runnable
"VM Periodic Task Thread" prio=10 tid=0x00007fdc880b3800 nid=0x12a5 waiting on condition
JNI global references: 1391
Heap
PSYoungGen total 17920K, used 1270K [0x00000000ecb00000, 0x00000000ede80000, 0x0000000100000000)
eden space 15872K, 8% used [0x00000000ecb00000,0x00000000ecc3d898,0x00000000eda80000)
from space 2048K, 0% used [0x00000000edc80000,0x00000000edc80000,0x00000000ede80000)
to space 2048K, 0% used [0x00000000eda80000,0x00000000eda80000,0x00000000edc80000)
ParOldGen total 39424K, used 0K [0x00000000c6200000, 0x00000000c8880000, 0x00000000ecb00000)
object space 39424K, 0% used [0x00000000c6200000,0x00000000c6200000,0x00000000c8880000)
PSPermGen total 21504K, used 2619K [0x00000000c1000000, 0x00000000c2500000, 0x00000000c6200000)
object space 21504K, 12% used [0x00000000c1000000,0x00000000c128edd8,0x00000000c2500000)
----------------------------------------------------------------------------------------------------------------------------
上面的信息中包含了当前JVM中所有运行的线程信息,其中在示例中我们启动的线程为main线程,其余的都是JVM自己创建的。
在打印的信息中,我们可以清楚的看见当前线程的调用上下文,可以很清楚的知道程序的运行情况。
并且我们在最后面还能看见当前虚拟机中的内存使用情况,青年世代,老年世代的信息等等...
PS: 在JDK1.5以上,我们可以通过在Java程序中调用Thread.getStackTrace()方法来进行堆栈的自动打印,使得线程堆栈的打印时机可编程控制。
文章知识点与官方知识档案匹配
Java技能树首页概览
89841 人正在系统学习中
点击阅读全文
打开CSDN,阅读体验更佳
jstack-查看Java进程的线程堆栈信息,锁定高消耗资源代码
jstack主要用来查看某个Java进程内的线程堆栈信息。语法格式如下: jstack[option]pid jstack[option]executable core jstack[option][server-id@]remote-hostname-or-ip 命令行参数选项说明如下: ...
011Java并发包018查看线程堆栈信息_执笔未来的博客
java.util.concurrent.ScheledThreadPoolExecutor$DelayedWorkQueue.take(ScheledThreadPoolExecutor.java:1088) java.util.concurrent.ScheledThreadPoolExecutor$DelayedWorkQueue.take(ScheledThreadPoolExecutor.java:809) java.util.concurre...
最新发布 jstack -- java堆栈常用排查指令
jstack -- java堆栈常用排查指令
继续访问
热门推荐 jstack 命令查看JAVA线程堆栈
JAVA堆栈信息实际生产中,可能由于开发以及测试未能全面覆盖的代码质量、性能问题,而引致线程挂起甚至崩溃。可能就需要查看堆栈信息来排查问题了。jps -lvmjps -lvm 用于查看当前机器上运行的java进程。C:\Users\Administrator>jps -lvm 7348 -Dosgi.requiredJavaVersion=1.8 -Dosgi.instance.area.defa
继续访问
Java多线程——查看线程堆栈信息
Java多线程——查看线程堆栈信息 摘要:本文主要介绍了查看线程堆栈信息的方法。 使用Thread类的getAllStackTraces()方法 方法定义 可以看到getAllStackTraces()方法的返回值是一个Map对象,key是Thread的实例,value是一个StackTraceElement实例数组: 1 public static Map<Thread, S...
继续访问
java堆栈常用排查指令
java 异常排查四板斧 1、查看java 堆栈线程信息 说明 jstack命令打印指定Java进程、核心文件或远程调试服务器的Java线程的Java堆栈跟踪信息。 对于每个Java框架,完整的类名,方法名, 字节码索引(BCI)和行号(如果有的话)被打印出来。 使用-m选项,jstack命令打印程序中所有线程的Java和本机帧 计数器(PC)。 对于每个本机帧,当可用时,将打印离PC最近的本机符号。 c++乱码的名字不会被修改。 要demangle c++名称,输出这个 命令可以管道到c++filt。 当
继续访问
java诊断工具-Arthas(thread命令)查看当前线程堆栈
cpu使用率与linux 命令top -H -p <pid>的线程CPU类似 1、支持一键展示当前最忙的前N个线程并打印堆栈 thread -n 3 没有线程ID,包含[Internal]表示为JVM内部线程,参考dashboard命令的介绍。 cpuUsage为采样间隔时间内线程的CPU使用率,与dashboard命令的数据一致。 deltaTime为采样间隔时间内线程的增量CPU时间,小于1ms时被取整显示为0ms。 time线程运行总CPU...
继续访问
java查看线程的堆栈信息
通过使用jps 命令获取需要监控的进程的pid,然后使用jstackpid 命令查看线程的堆栈信息。 通过jstack命令可以获取当前进程的所有线程信息。 每个线程堆中信息中,都可以查看到线程ID、线程的状态(wait、sleep、running 等状态)、是否持有锁信息等。 jstack -l <pid> >jvm_listlocks.txt 转...
继续访问
java 查看线程堆栈信息_Java多线程——查看线程堆栈信息
java多线程——查看线程堆栈信息摘要:本文主要介绍了查看线程堆栈信息的方法。使用thread类的getallstacktraces()方法方法定义可以看到getallstacktraces()方法的返回值是一个map对象,key是thread的实例,value是一个stacktraceelement实例数组:1 public static map getallstacktraces()使用可以使...
继续访问
java线程堆栈信息分析
java堆栈信息分析
继续访问
java 查看堆栈_javap 命令查看堆栈中信息
javap命令是对.java文件进行反编译,通过这个命令可以看到堆栈中是怎么压栈和出栈的已经执行顺序,这里简单解释下javap的简单的使用,下面举个例子:题目:i++ 和++i的区别解释:简单点说 这个问题都不难回答,这里就不说了,但是实际上堆栈中区别也是老大了(这里就用到了javap命令), 步骤:1.在任意一个盘下面建一个名为Test.java的文件(文件名可以随意命名)代码如下:public...
继续访问
java 查看线程堆栈信息_jstack-查看Java进程的线程堆栈信息,锁定高消耗资源代码。...
jstack主要用来查看某个Java进程内的线程堆栈信息。语法格式如下:jstack[option]pidjstack[option]executablecorejstack[option][server-id@]remote-hostname-or-ip命令行参数选项说明如下:-llonglistings,会打印出额外的锁信息,在发生死锁时可以用jstack-lpid来观察...
继续访问
java堆栈信息怎么看_线程堆栈信息怎么看? - cs_person的个人空间 - OSCHINA - 中文开源技术交流社区...
一条线程堆栈信息大概长成下面这个样子:RMI TCP Connection(267865)-172.16.5.25" daemon prio=10 tid=0x00007fd508371000 nid=0x55ae waiting for monitor entry [0x00007fd4f8684000]java.lang.Thread.State: BLOCKED (on object m...
继续访问
线程堆栈信息怎么看?
一条线程堆栈信息大概长成下面这个样子: RMI TCP Connection(267865)-172.16.5.25" daemon prio=10 tid=0x00007fd508371000 nid=0x55ae waiting for monitor entry [0x00007fd...
继续访问
java的栈和堆
栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 Java 的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在...
继续访问
查看java线程_【JAVA】Java线程堆栈信息查看
如何获得线程的堆栈信息?线上服务器cpu 100%了,该如何排查问题?1.top命令查询哪个pid进程占用cpu高(ps -ef|grep java 获取PID号)2.通过 top -Hp pid 可以查看该进程下各个线程的cpu使用情况,获取占用cpu高的线程id3.执行命令:printf "%X\n" 线程tid(用于获取占用cpu高的线程id的16进制数)4.执行命令:jstack pid ...
继续访问
kill -3 java_kill -3 PID命令获取java应用堆栈信息
一、应用场景:当linux服务器出现异常情况(响应缓慢,负载持续飙升)并且服务器没有安装对应的包而无法使用jstack等命令时,可以使用linux的kill相关命令打印堆栈信息。命令格式:kill -3 PID二、执行步骤:2.1、获取java进程的PIDps -ef|grep java结果的第二列数字就是进程对应的pid。2.2、kill -3 PID(1)如果项目通过Tomcat进行发布(普通...
继续访问
jstack 工具 查看JVM堆栈信息
1|0介绍 jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于打印出给定的java进程ID或corefile或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使用方式只支持以下的这种方式: jstack [-l] pid 主要分为两个功能: a. 针对活着的进程做本地的或远程的线程mp; b. 针对core文件做线程mp。 jstack用于生成java虚拟机当前时刻的线程快照。线程快照是...
继续访问
linux查看java堆栈
1、查看JAVA进程JVM参数 jinfo -flags pid(进程号) -XX:CICompilerCount=2 最大的并行编译数 -XX:InitialHeapSize=16777216 JVM 的初始堆内存大小 -XX:MaxHeapSize=257949696 JVM 的最大堆内存大小 -XX:MaxNewSize=85983232 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=5570560 -XX:OldSize=11206656 2、JVM 查看.
继续访问
Linux 如何查看一个进程的堆栈
有两种方法:第一种:pstack 进程ID第二种,使用gdb 然后attach 进程ID,然后再使用命令 thread apply all bt 两种方法都可以列出进程所有的线程的当前的调用栈。不过,使用gdb的方法,还可以查看某些信息,例如局部变量,指针等。不过,如果只看调用栈的话,pstack还是很方便的。
继续访问
JAVA获取堆栈信息
1. 通过Throwable获取 StackTraceElement[] stackTrace = new Throwable().getStackTrace(); 2. 通过Thread获取 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
继续访问
java 查看线程栈大小_基于 Java 线程栈的问题排查
除日志外,还有没有别的方式跟踪线上服务问题呢?或者,跟踪并排除日志里无法发现的问题?方法当然是有的,就是通过现场快照定位并发现问题。我们所说的现场,主要指这两方面:Java 线程栈。线程栈是Java线程工作的快照,可以获得当前线程在做什么;Java 内存堆。堆是JVM的内存快照,可以获取内存分配相关信息。
❻ 如何查看java虚拟机堆内存的参数值
请确保java_home/bin配置到path环境变量下,因为这些工具都在jdk的bin目录下
jps(JVM Process Status Tool):JVM机进程状况工具
用来查看基于HotSpot JVM里面所有进程的具体状态, 包括进程ID,进程启动的路径等等。与unix上的ps类似,用来显示本地有权限的java进程,可以查看本地运行着几个java程序,并显示他们的进程号。使用jps时,不需要传递进程号做为参数。
Jps也可以显示远程系统上的JAVA进程,这需要远程服务上开启了jstat服务,以及RMI注及服务,不过常用都是对本对的JAVA进程的查看。
命令格式:jps [ options ] [ hostid ]
常用参数说明:
-m 输出传递给main方法的参数,如果是内嵌的JVM则输出为null。
-l 输出应用程序主类的完整包名,或者是应用程序JAR文件的完整路径。
-v 输出传给JVM的参数。
例如:
C:\Users\Administrator>jps -lmv
1796 -Dosgi.requiredJavaVersion=1.5 -Xms40m -Xmx512m -XX:MaxPermSize=256m
7340 sun.tools.jps.Jps -lmv -Denv.class.path=.;D:\DevTools\VM\jdk1.6.0_31\\lib\dt.jar;D:\DevTools\VM\jdk1.6.0_31\\lib\tools.jar; -Dapplication.home=D:\DevTools\VM\jdk1.6.0_31 -Xms8m
其中pid为1796的是我的eclipse进程,pid为7340的是jps命令本身的进程
jinfo(Configuration Info for Java):JVM配置信息工具
可以输出并修改运行时的java 进程的opts。用处比较简单,用于输出JAVA系统参数及命令行参数
命令格式:jinfo [ options ] [ pid ]
常用参数说明:
-flag 输出,修改,JVM命令行参数
例如:
C:\Users\Administrator>jinfo 1796
将会打印出很多jvm运行时参数信息,由于比较长这里不再打印出来,可以自己试试,内容一目了然
Jstack(Stack Trace for Java):JVM堆栈跟踪工具
jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64“
命令格式:jstack [ option ] pid
常用参数说明:
-F 当’jstack [-l] pid’没有相应的时候强制打印栈信息
-l 长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.
-m 打印java和native c/c++框架的所有栈信息.
-h | -help打印帮助信息
例如:
C:\Users\Administrator>jstack 1796
2013-05-22 11:42:38
Full thread mp Java HotSpot(TM) Client VM (20.6-b01 mixed mode):
"Worker-30" prio=6 tid=0x06514c00 nid=0x1018 in Object.wait() [0x056af000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
- locked <0x1ad84a90> (a org.eclipse.core.internal.jobs.WorkerPool)
at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)
......
......
......
......
jstat(JVM statistics Monitoriing Tool):JVM统计信息监视工具
对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控
命令格式:jstat [ option pid [interval [ s | ms ] [count] ] ]
常用参数说明:
-gcutil 输出已使用空间占总空间的百分比
-gccapacity 输出堆中各个区域使用到的最大和最小空间
例如:每隔1秒监控jvm内存一次,共监控5次
C:\Users\Administrator>jstat -gccapacity 1796 1s 5
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC PGCMN PGCMX PGC PC YGC FGC
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 96
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 96
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 96
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 96
13632.0 174720.0 40896.0 4032.0 4032.0 32832.0 27328.0 349568.0 81684.0 81684.0 12288.0 262144.0 80640.0 80640.0 42 97
C:\Users\Administrator>jstat -gcutil 1796 1s 5
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
0.00 0.00 0.52 53.35 99.77 42 0.513 99 38.119 38.632
一些术语的中文解释:
S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC:年轻代中Eden(伊甸园)的容量 (字节)
EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
OC:Old代的容量 (字节)
OU:Old代目前已使用空间 (字节)
PC:Perm(持久代)的容量 (字节)
PU:Perm(持久代)目前已使用空间 (字节)
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
NGCMN:年轻代(young)中初始化(最小)的大小 (字节)
NGCMX:年轻代(young)的最大容量 (字节)
NGC:年轻代(young)中当前的容量 (字节)
OGCMN:old代中初始化(最小)的大小 (字节)
OGCMX:old代的最大容量 (字节)
OGC:old代当前新生成的容量 (字节)
PGCMN:perm代中初始化(最小)的大小 (字节)
PGCMX:perm代的最大容量 (字节)
PGC:perm代当前新生成的容量 (字节)
S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E:年轻代中Eden(伊甸园)已使用的占当前容量百分比
O:old代已使用的占当前容量百分比
P:perm代已使用的占当前容量百分比
S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节)
S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节)
ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)
DSS:当前需要survivor(幸存区)的容量 (字节)(Eden区已满)
TT: 持有次数限制
MTT : 最大持有次数限制
jmap( Memory Map for Java):JVM内存映像工具
打印出某个java进程(使用pid)内存内的所有‘对象’的情况(如:产生那些对象,及其数量)
命令格式:jmap [ option ] pid
常用参数说明:
-mp:[live,]format=b,file=<filename> 使用二进制形式输出jvm的heap内容到文件中, live子选项是可选的,假如指定live选项,那么只输出活的对象到文件.
-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量.
-F 强迫.在pid没有相应的时候使用-mp或者-histo参数. 在这个模式下,live子参数无效.
例如:以二进制形式输入当前堆内存映像到文件data.hprof中
jmap -mp:live,format=b,file=data.hprof 1796
生成的文件可以使用jhat工具进行分析,在OOM(内存溢出)时,分析大对象,非常有用
通过使用如下参数启动JVM,也可以获取到mp文件:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./java_pid<pid>.hprof
在jvm发生内存溢出时生成内存映像文件
jhat(JVM Heap Analysis Tool):JVM堆转储快照分析工具
用于对JAVA heap进行离线分析的工具,他可以对不同虚拟机中导出的heap信息文件进行分析,如LINUX上导出的文件可以拿到WINDOWS上进行分析,可以查找诸如内存方面的问题。
命令格式:jhat mpfile(jmap生成的文件)
例如:分析jmap导出的内存映像
jhat data.hprof
执行成功后,访问http://localhost:7000即可查看内存信息,
MAT(Memory Analyzer Tool):一个基于Eclipse的内存分析工具
官网: http://www.eclipse.org/mat/
update:http://download.eclipse.org/mat/1.2/update-site/
这是eclipse的一个插件,安装后可以打开xxx.hprof文件,进行分析,比jhat更方便使用,有些时候由于线上xxx.hprof文件过大,直接使用jhat进行初步分析了,可以的话拷贝到本地分析效果更佳。
图形化监控工具:
在JDK安装目录bin下面有两个可视化监控工具
1. JConsole(Java Monitoring and Management Console) 基于JMX的可视化管理工具。
2. VisualVM(All-in-one Java Troubleshooting Tool)随JDK发布的最强大的运行监视和故障处理程序。
推荐使用VisualVM,他有很多插件,可以更方便的监控运行时JVM
❼ 手机调试Android程序出异常时不打印堆栈信息
打印堆栈是调试的常用方法,一般在系统异常时,我们可以将异常情况下的堆栈打印出来,这样十分方便错误查找。实际上还有另外一个非常有用的功能:分析代码的行为。android代码太过庞大复杂了,完全的静态分析经常是无从下手,因此通过打印堆栈的动态分析也十分必要。
Android打印堆栈的方法,简单归类一下
1. zygote的堆栈mp
实际上这个可以同时mp java线程及native线程的堆栈,对于java线程,java堆栈和native堆栈都可以得到。
使用方法很简单,直接在adb shell或串口中输入:
[plain] view plain
kill -3 <pid>
输出的trace会保存在 /data/anr/traces.txt文件中。这个需要注意,如果没有 /data/anr/这个目录或/data/anr/traces.txt这个文件,需要手工创建一下,并设置好读写权限。
如果需要在代码中,更容易控制堆栈的输出时机,可以用以下命令获取zygote的core mp:
[java] view plain
Process.sendSignal(pid, Process.SIGNAL_QUIT);
原理和命令行是一样的。
不过需要注意两点:
adb shell可能会没有权限,需要root。
android 4.2中关闭了native thread的堆栈打印,详见 dalvik/vm/Thread.cpp的mpNativeThread方法:
[cpp] view plain
dvmPrintDebugMessage(target,
"\"%s\" sysTid=%d nice=%d sched=%d/%d cgrp=%s\n",
name, tid, getpriority(PRIO_PROCESS, tid),
schedStats.policy, schedStats.priority, schedStats.group);
mpSchedStat(target, tid);
// Temporarily disabled collecting native stacks from non-Dalvik
// threads because sometimes they misbehave.
//dvmDumpNativeStack(target, tid);
Native堆栈的打印被关掉了!不过对于大多数情况,可以直接将这个注释打开。
2. debuggerd的堆栈mp
debuggerd是android的一个daemon进程,负责在进程异常出错时,将进程的运行时信息mp出来供分析。debuggerd生 成的coremp数据是以文本形式呈现,被保存在 /data/tombstone/ 目录下(名字取的也很形象,tombstone是墓碑的意思),共可保存10个文件,当超过10个时,会覆盖重写最早生成的文件。从4.2版本开 始,debuggerd同时也是一个实用工具:可以在不中断进程执行的情况下打印当前进程的native堆栈。使用方法是:
[plain] view plain
debuggerd -b <pid>
这可以协助我们分析进程执行行为,但最最有用的地方是:它可以非常简单的定位到native进程中锁死或错误逻辑引起的死循环的代码位置。
3. java代码中打印堆栈
Java代码打印堆栈比较简单, 堆栈信息获取和输出,都可以通过Throwable类的方法实现。目前通用的做法是在java进程出现需要注意的异常时,打印堆栈,然后再决定退出或挽救。通常的方法是使用exception的printStackTrace()方法:
[java] view plain
try {
...
} catch (RemoteException e) {
e.printStackTrace();
...
}
当然也可以只打印堆栈不退出,这样就比较方便分析代码的动态运行情况。Java代码中插入堆栈打印的方法如下:
[java] view plain
Log.d(TAG,Log.getStackTraceString(new Throwable()));
4. C++代码中打印堆栈
C++也是支持异常处理的,异常处理库中,已经包含了获取backtrace的接口,Android也是利用这个接口来打印堆栈信息的。在Android的C++中,已经集成了一个工具类CallStack,在libutils.so中。使用方法:
[cpp] view plain
#include <utils/CallStack.h>
...
CallStack stack;
stack.update();
stack.mp();
使用方式比较简单。目前Andoid4.2版本已经将相关信息解析的很到位,符号表查找,demangle,偏移位置校正都做好了。
[plain] view plain
5. C代码中打印堆栈
C代码,尤其是底层C库,想要看到调用的堆栈信息,还是比较麻烦的。 CallStack肯定是不能用,一是因为其实C++写的,需要重新封装才能在C中使用,二是底层库反调上层库的函数,会造成链接器循环依赖而无法链接。 不过也不是没有办法,可以通过android工具类CallStack实现中使用的unwind调用及符号解析函数来处理。
这里需要注意的是,为解决链接问题,最好使用dlopen方式,查找需要用到的接口再直接调用,这样会比较简单。如下为相关的实现代码,只需要在要 打印的文件中插入此部分代码,然后调用getCallStack()即可,无需包含太多的头文件和修改Android.mk文件:
[cpp] view plain
#define MAX_DEPTH 31
#define MAX_BACKTRACE_LINE_LENGTH 800
#define PATH "/system/lib/libcorkscrew.so"
typedef ssize_t (*unwindFn)(backtrace_frame_t*, size_t, size_t);
typedef void (*unwindSymbFn)(const backtrace_frame_t*, size_t, backtrace_symbol_t*);
typedef void (*unwindSymbFreeFn)(backtrace_symbol_t*, size_t);
static void *gHandle = NULL;
static int getCallStack(void){
ssize_t i = 0;
ssize_t result = 0;
ssize_t count;
backtrace_frame_t mStack[MAX_DEPTH];
backtrace_symbol_t symbols[MAX_DEPTH];
unwindFn unwind_backtrace = NULL;
unwindSymbFn get_backtrace_symbols = NULL;
unwindSymbFreeFn free_backtrace_symbols = NULL;
// open the so.
if(gHandle == NULL) gHandle = dlopen(PATH, RTLD_NOW);
// get the interface for unwind and symbol analyse
if(gHandle != NULL) unwind_backtrace = (unwindFn)dlsym(gHandle, "unwind_backtrace");
if(gHandle != NULL) get_backtrace_symbols = (unwindSymbFn)dlsym(gHandle, "get_backtrace_symbols");
if(gHandle != NULL) free_backtrace_symbols = (unwindSymbFreeFn)dlsym(gHandle, "free_backtrace_symbols");
if(!gHandle ||!unwind_backtrace ||!get_backtrace_symbols || !free_backtrace_symbols ){
ALOGE("Error! cannot get unwind info: handle:%p %p %p %p",
gHandle, unwind_backtrace, get_backtrace_symbols, free_backtrace_symbols );
return result;
}
count= unwind_backtrace(mStack, 1, MAX_DEPTH);
get_backtrace_symbols(mStack, count, symbols);
for (i = 0; i < count; i++) {
char line[MAX_BACKTRACE_LINE_LENGTH];
const char* mapName = symbols[i].map_name ? symbols[i].map_name : "<unknown>";
const char* symbolName =symbols[i].demangled_name ? symbols[i].demangled_name : symbols[i].symbol_name;
size_t fieldWidth = (MAX_BACKTRACE_LINE_LENGTH - 80) / 2;
if (symbolName) {
uint32_t pc_offset = symbols[i].relative_pc - symbols[i].relative_symbol_addr;
if (pc_offset) {
snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s+%u)",
i, symbols[i].relative_pc, fieldWidth, mapName,
fieldWidth, symbolName, pc_offset);
} else {
snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s)",
i, symbols[i].relative_pc, fieldWidth, mapName,
fieldWidth, symbolName);
}
} else {
snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s",
i, symbols[i].relative_pc, fieldWidth, mapName);
}
ALOGD("%s", line);
}
free_backtrace_symbols(symbols, count);
return result;
}
对sched_policy.c的堆栈调用分析如下,注意具体是否要打印,在哪里打印,还可以通过pid、uid、property等来控制一下,这样就不会被淹死在trace的汪洋大海中。
[plain] view plain
D/SchedPolicy( 1350): #00 pc 0000676c /system/lib/libcutils.so
D/SchedPolicy( 1350): #01 pc 00006b3a /system/lib/libcutils.so (set_sched_policy+49)
D/SchedPolicy( 1350): #02 pc 00010e82 /system/lib/libutils.so (androidSetThreadPriority+61)
D/SchedPolicy( 1350): #03 pc 00068104 /system/lib/libandroid_runtime.so (android_os_Process_setThreadPriority(_JNIEnv*, _jobject*, int, int)+7)
D/SchedPolicy( 1350): #04 pc 0001e510 /system/lib/libdvm.so (dvmPlatformInvoke+112)
D/SchedPolicy( 1350): #05 pc 0004d6aa /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+417)
D/SchedPolicy( 1350): #06 pc 00027920 /system/lib/libdvm.so
D/SchedPolicy( 1350): #07 pc 0002b7fc /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
D/SchedPolicy( 1350): #08 pc 00060c30 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+271)
D/SchedPolicy( 1350): #09 pc 0004cd34 /system/lib/libdvm.so
D/SchedPolicy( 1350): #10 pc 00049382 /system/lib/libandroid_runtime.so
D/SchedPolicy( 1350): #11 pc 00065e52 /system/lib/libandroid_runtime.so
D/SchedPolicy( 1350): #12 pc 0001435e /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+57)
D/SchedPolicy( 1350): #13 pc 00016f5a /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+513)
D/SchedPolicy( 1350): #14 pc 00017380 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+183)
D/SchedPolicy( 1350): #15 pc 0001b160 /system/lib/libbinder.so
D/SchedPolicy( 1350): #16 pc 00011264 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)
D/SchedPolicy( 1350): #17 pc 000469bc /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+63)
D/SchedPolicy( 1350): #18 pc 00010dca /system/lib/libutils.so
D/SchedPolicy( 1350): #19 pc 0000e3d8 /system/lib/libc.so (__thread_entry+72)
D/SchedPolicy( 1350): #20 pc 0000dac4 /system/lib/libc.so (pthread_create+160)
D/SchedPolicy( 1350): #00 pc 0000676c /system/lib/libcutils.so
D/SchedPolicy( 1350): #01 pc 00006b3a /system/lib/libcutils.so (set_sched_policy+49)
D/SchedPolicy( 1350): #02 pc 00016f26 /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+461)
D/SchedPolicy( 1350): #03 pc 00017380 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+183)
D/SchedPolicy( 1350): #04 pc 0001b160 /system/lib/libbinder.so
D/SchedPolicy( 1350): #05 pc 00011264 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)
D/SchedPolicy( 1350): #06 pc 000469bc /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+63)
D/SchedPolicy( 1350): #07 pc 00010dca /system/lib/libutils.so
D/SchedPolicy( 1350): #08 pc 0000e3d8 /system/lib/libc.so (__thread_entry+72)
D/SchedPolicy( 1350): #09 pc 0000dac4 /system/lib/libc.so (pthread_create+160)
6. 其它堆栈信息查询