存档

‘linux’ 分类的存档

linux 中查看某个单进程程序运行所占内存(linux proc status statm详解)

2011年4月8日 没有评论

linux 中查看 某个单进程程序运行所占内存所占的内存空间,设pid为进程id(ps aux| grep ‘processName’获得),查看/proc/pid/statm和/proc/pid/status即可

proc/[pid]/statm
              Provides information about memory usage, measured in pages.  The
              columns are:

                  size       total program size
                             (same as VmSize in /proc/[pid]/status)
                  resident   resident set size
                             (same as VmRSS in /proc/[pid]/status)
                  share      shared pages (from shared mappings)
                  text       text (code)
                  lib        library (unused in Linux 2.6)
                  data       data + stack
                  dt         dirty pages (unused in Linux 2.6)

       /proc/[pid]/status
              Provides much of the information in /proc/[pid]/stat and
              /proc/[pid]/statm in a format that's easier for humans to parse.
              Here's an example:

                  $ cat /proc/$$/status
                  Name:   bash
                  State:  S (sleeping)
                  Tgid:   3515
                  Pid:    3515
                  PPid:   3452
                  TracerPid:      0
                  Uid:    1000    1000    1000    1000
                  Gid:    100     100     100     100
                  FDSize: 256
                  Groups: 16 33 100
                  VmPeak:     9136 kB
                  VmSize:     7896 kB
                  VmLck:         0 kB
                  VmHWM:      7572 kB
                  VmRSS:      6316 kB
                  VmData:     5224 kB
                  VmStk:        88 kB
                  VmExe:       572 kB
                  VmLib:      1708 kB
                  VmPTE:        20 kB
                  Threads:        1
                  SigQ:   0/3067
                  SigPnd: 0000000000000000
                  ShdPnd: 0000000000000000
                  SigBlk: 0000000000010000
                  SigIgn: 0000000000384004
                  SigCgt: 000000004b813efb
                  CapInh: 0000000000000000
                  CapPrm: 0000000000000000
                  CapEff: 0000000000000000
                  CapBnd: ffffffffffffffff
                  Cpus_allowed:   00000001
                  Cpus_allowed_list:      0
                  Mems_allowed:   1
                  Mems_allowed_list:      0
                  voluntary_ctxt_switches:        150
                  nonvoluntary_ctxt_switches:     545

              The fields are as follows:

              * Name: Command run by this process.

              * State: Current state of the process.  One of "R (running)", "S
                (sleeping)", "D (disk sleep)", "T (stopped)", "T (tracing stop)", "Z
                (zombie)", or "X (dead)".

              * Tgid: Thread group ID (i.e., Process ID).

              * Pid: Thread ID (see gettid(2)).

              * TracerPid: PID of process tracing this process (0 if not being
                traced).

              * Uid, Gid: Real, effective, saved set, and file system UIDs (GIDs).

              * FDSize: Number of file descriptor slots currently allocated.

              * Groups: Supplementary group list.

              * VmPeak: Peak virtual memory size.

              * VmSize: Virtual memory size.

              * VmLck: Locked memory size (see mlock(3)).

              * VmHWM: Peak resident set size ("high water mark").

              * VmRSS: Resident set size.

              * VmData, VmStk, VmExe: Size of data, stack, and text segments.

              * VmLib: Shared library code size.

              * VmPTE: Page table entries size (since Linux 2.6.10).

              * Threads: Number of threads in process containing this thread.

              * SigPnd, ShdPnd: Number of signals pending for thread and for process
                as a whole (see pthreads(7) and signal(7)).

              * SigBlk, SigIgn, SigCgt: Masks indicating signals being blocked,
                ignored, and caught (see signal(7)).

              * CapInh, CapPrm, CapEff: Masks of capabilities enabled in inheritable,
                permitted, and effective sets (see capabilities(7)).

              * CapBnd: Capability Bounding set (since kernel 2.6.26, see
                capabilities(7)).

              * Cpus_allowed: Mask of CPUs on which this process may run (since Linux
                2.6.24, see cpuset(7)).

              * Cpus_allowed_list: Same as previous, but in "list format" (since
                Linux 2.6.26, see cpuset(7)).

              * Mems_allowed: Mask of memory nodes allowed to this process (since
                Linux 2.6.24, see cpuset(7)).

              * Mems_allowed_list: Same as previous, but in "list format" (since
                Linux 2.6.26, see cpuset(7)).

              * voluntary_context_switches, nonvoluntary_context_switches: Number of
                voluntary and involuntary context switches (since Linux 2.6.23).

示例代码下载

Popularity: 57%

分类: C++, linux 标签:

【转】Linux下的段错误产生的原因及调试方法

2011年3月1日 没有评论

编者按:最近用gdb调试程序,发现功能还是比较强大的,下面是gdb调试段错误的一些方法

这篇文章好多地方都有,最早的我看到的是这个,我也是从这里转的:http://www.upsdn.net/html/2006-11/775.html

简而言之,产生段错误就是访问了错误的内存段,一般是你没有权限,或者根本就不存在对应的物理内存,尤其常见的是访问0地址.

一般来说,段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gdtr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的gdt表,后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向的gdt是由以64位为一个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。一旦一个程序发生了越界访问,cpu就会产生相应的异常保护,于是segmentation fault就出现了.

在编程中以下几类做法容易导致段错误,基本是是错误地使用指针引起的

1)访问系统数据区,尤其是往  系统保护的内存地址写数据
最常见就是给一个指针以0地址
2)内存越界(数组越界,变量类型不一致等) 访问到不属于你的内存区域

解决方法

我们在用C/C++语言写程序的时侯,内存管理的绝大部分工作都是需要我们来做的。实际上,内存管理是一个比较繁琐的工作,无论你多高明,经验多丰富,难 免会在此处犯些小错误,而通常这些错误又是那么的浅显而易于消除。但是手工“除虫”(debug),往往是效率低下且让人厌烦的,本文将就”段错误”这个 内存访问越界的错误谈谈如何快速定位这些”段错误”的语句。
下面将就以下的一个存在段错误的程序介绍几种调试方法:

1  dummy_function (void)
2  {
3          unsigned char *ptr = 0×00;
4          *ptr = 0×00;
5  }
6
7  int main (void)
8  {
9          dummy_function ();
10
11          return 0;
12  }

作为一个熟练的C/C++程序员,以上代码的bug应该是很清楚的,因为它尝试操作地址为0的内存区域,而这个内存区域通常是不可访问的禁区,当然就会出错了。我们尝试编译运行它:

xiaosuo@gentux test $ ./a.out
段错误

果然不出所料,它出错并退出了。
1.利用gdb逐步查找段错误:
这种方法也是被大众所熟知并广泛采用的方法,首先我们需要一个带有调试信息的可执行程序,所以我们加上“-g -rdynamic”的参数进行编译,然后用gdb调试运行这个新编译的程序,具体步骤如下:

xiaosuo@gentux test $ gcc -g -rdynamic d.c
xiaosuo@gentux test $ gdb ./a.out
GNU gdb 6.5
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB.  Type “show warranty” for details.
This GDB was configured as “i686-pc-linux-gnu”…Using host libthread_db library “/lib/libthread_db.so.1″.

(gdb) r
Starting program: /home/xiaosuo/test/a.out

Program received signal SIGSEGV, Segmentation fault.
0×08048524 in dummy_function () at d.c:4
4               *ptr = 0×00;
(gdb)

哦?!好像不用一步步调试我们就找到了出错位置d.c文件的第4行,其实就是如此的简单。
从这里我们还发现进程是由于收到了SIGSEGV信号而结束的。通过进一步的查阅文档(man 7 signal),我们知道SIGSEGV默认handler的动作是打印”段错误”的出错信息,并产生Core文件,由此我们又产生了方法二。
2.分析Core文件:
Core文件是什么呢?

The  default action of certain signals is to cause a process to terminate and produce a core dump file, a disk file containing an image of the process’s memory  at the time of termination.  A list of the signals which cause a process to dump core can be found in signal(7).

以 上资料摘自man page(man 5 core)。不过奇怪了,我的系统上并没有找到core文件。后来,忆起为了渐少系统上的拉圾文件的数量(本人有些洁癖,这也是我喜欢Gentoo的原因 之一),禁止了core文件的生成,查看了以下果真如此,将系统的core文件的大小限制在512K大小,再试:

xiaosuo@gentux test $ ulimit -c
0
xiaosuo@gentux test $ ulimit -c 1000
xiaosuo@gentux test $ ulimit -c
1000
xiaosuo@gentux test $ ./a.out
段错误 (core dumped)
xiaosuo@gentux test $ ls
a.out  core  d.c  f.c  g.c  pango.c  test_iconv.c  test_regex.c

core文件终于产生了,用gdb调试一下看看吧:

xiaosuo@gentux test $ gdb ./a.out core
GNU gdb 6.5
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB.  Type “show warranty” for details.
This GDB was configured as “i686-pc-linux-gnu”…Using host libthread_db library “/lib/libthread_db.so.1″.

warning: Can’t read pathname for load map: 输入/输出错误.
Reading symbols from /lib/libc.so.6…done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2…done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./a.out’.
Program terminated with signal 11, Segmentation fault.
#0  0×08048524 in dummy_function () at d.c:4
4               *ptr = 0×00;

哇,好历害,还是一步就定位到了错误所在地,佩服一下Linux/Unix系统的此类设计。
接着考虑下去,以前用windows系统下的ie的时侯,有时打开某些网页,会出现“运行时错误”,这个时侯如果恰好你的机器上又装有windows的编译器的话,他会弹出来一个对话框,问你是否进行调试,如果你选择是,编译器将被打开,并进入调试状态,开始调试。
Linux下如何做到这些呢?我的大脑飞速地旋转着,有了,让它在SIGSEGV的handler中调用gdb,于是第三个方法又诞生了:
3.段错误时启动调试:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>

void dump(int signo)
{
char buf[1024];
char cmd[1024];
FILE *fh;

snprintf(buf, sizeof(buf), “/proc/%d/cmdline”, getpid());
if(!(fh = fopen(buf, “r”)))
exit(0);
if(!fgets(buf, sizeof(buf), fh))
exit(0);
fclose(fh);
if(buf[strlen(buf) - 1] == ‘\n’)
buf[strlen(buf) - 1] = ‘\0′;
snprintf(cmd, sizeof(cmd), “gdb %s %d”, buf, getpid());
system(cmd);

exit(0);
}

void
dummy_function (void)
{
unsigned char *ptr = 0×00;
*ptr = 0×00;
}

int
main (void)
{
signal(SIGSEGV, &dump);
dummy_function ();

return 0;
}

编译运行效果如下:

xiaosuo@gentux test $ gcc -g -rdynamic f.c
xiaosuo@gentux test $ ./a.out
GNU gdb 6.5
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB.  Type “show warranty” for details.
This GDB was configured as “i686-pc-linux-gnu”…Using host libthread_db library “/lib/libthread_db.so.1″.

Attaching to program: /home/xiaosuo/test/a.out, process 9563
Reading symbols from /lib/libc.so.6…done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2…done.
Loaded symbols for /lib/ld-linux.so.2
0xffffe410 in __kernel_vsyscall ()
(gdb) bt
#0  0xffffe410 in __kernel_vsyscall ()
#1  0xb7ee4b53 in waitpid () from /lib/libc.so.6
#2  0xb7e925c9 in strtold_l () from /lib/libc.so.6
#3  0×08048830 in dump (signo=11) at f.c:22
#4  <signal handler called>
#5  0x0804884c in dummy_function () at f.c:31
#6  0×08048886 in main () at f.c:38

怎么样?是不是依旧很酷?
以上方法都是在系统上有gdb的前提下进行的,如果没有呢?其实glibc为我们提供了此类能够dump栈内容的函数簇,详见/usr/include/execinfo.h(这些函数都没有提供man page,难怪我们找不到),另外你也可以通过gnu的手册进行学习。
4.利用backtrace和objdump进行分析:
重写的代码如下:

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

/* A dummy function to make the backtrace more interesting. */
void
dummy_function (void)
{
unsigned char *ptr = 0×00;
*ptr = 0×00;
}

void dump(int signo)
{
void *array[10];
size_t size;
char **strings;
size_t i;

size = backtrace (array, 10);
strings = backtrace_symbols (array, size);

printf (“Obtained %zd stack frames.\n”, size);

for (i = 0; i < size; i++)
printf (“%s\n”, strings[i]);

free (strings);

exit(0);
}

int
main (void)
{
signal(SIGSEGV, &dump);
dummy_function ();

return 0;
}

编译运行结果如下:

xiaosuo@gentux test $ gcc -g -rdynamic g.c
xiaosuo@gentux test $ ./a.out
Obtained 5 stack frames.
./a.out(dump+0×19) [0x80486c2]
[0xffffe420]
./a.out(main+0×35) [0x804876f]
/lib/libc.so.6(__libc_start_main+0xe6) [0xb7e02866]
./a.out [0x8048601]

这次你可能有些失望,似乎没能给出足够的信息来标示错误,不急,先看看能分析出来什么吧,用objdump反汇编程序,找到地址0x804876f对应的代码位置:

xiaosuo@gentux test $ objdump -d a.out
8048765:       e8 02 fe ff ff          call   804856c <signal@plt>
804876a:       e8 25 ff ff ff          call   8048694 <dummy_function>
804876f:       b8 00 00 00 00          mov    $0×0,%eax
8048774:       c9                      leave

我们还是找到了在哪个函数(dummy_function)中出错的,信息已然不是很完整,不过有总比没有好的啊!
后记:
本文给出了分析”段错误”的几种方法,不要认为这是与孔乙己先生的”回”字四种写法一样的哦,因为每种方法都有其自身的适用范围和适用环境,请酌情使用,或遵医嘱。

对于段错误这种问题。可以分析以下原因:
(1):指针非法,比如使用没有初始化的指针(没有为此指针指向的对象分配空间),或着Free掉之后再次使用。
(2):数组访问越界,访问的元素下标超过数组围长
(3):缓存溢出,对于这种while(1) {do}的程序,这个问题最容易发生,多此sprintf或着strcat有可能将某个
buff填满,溢出,所以每次使用前,最好memset一下,不过要是一开始就是段错误,而不是运行了一会儿出现的,(3)的可能性就比较小。

Popularity: 16%

分类: C++, linux 标签:

无法在构造函数中实现动态绑定

2010年6月18日 没有评论

今天和室友以及师弟们讨论Builder模式的时候,提到了一种思想,就是利用覆盖父类中的某些函数,来解决生成不同对象的问题。

回来的路上对这个是否能在构造函数中实现动态绑定拿不定主意,回来后写了如下代码测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <IOSTREAM>
 
class Base {
public:
 Base();
 virtual void compose();
protected:
 virtual void A();
 virtual void B();
 virtual void C();
 
};
Base::Base()
{
 A();
 B();
 C();
}
 
void Base::compose(){
 A();
 B();
 C();
}
 
void Base::A()
{
 std::cout<<"in Base A"<<std::endl;
}
 
void Base::B()
{
 std::cout<<"in Base B"<<std::endl;
}
 
void Base::C()
{
 std::cout<<"in Base C"<<std::endl;
}
 
class Derived : public Base{
public:
 void B();
};
 
void Derived::B()
{
 std::cout<<"in Derived B"<<std::endl;
}
 
int main(int argc, char* argv[])
{
 //Derived *obj = new Derived();
 Base *obj = new Derived();
 obj->compose();
 delete obj;
 return 0;
}

输出结果如下:

in Base A
 in Base B
 in Base C
 in Base A
 in Derived B
 in Base C
 Press any key to continue

从输出结果可以看出在构造函数中无法实现动态绑定,但是在非构造函数中完全没有问题。
注:
如果在linux/unix中运行上述代码,需要将
“#include <IOSTREAM>” 改成 “#include <iostream>” (windows 不区分大小写)

linux/unix中编译方法:

gcc -lstdc++ -o build  build.cpp 或者 g++ -o build  build.cpp

运行方法:

./build

(加上-lstdc++在linux系统会自动在/usr/lib/下面中找stdc++.a stdc++.so.* )

Popularity: 11%

分类: C++, linux 标签:

freebsd,linux,windows通过SSH翻墙方法汇总

2010年6月10日 4 条评论

通过ssh翻墙的思路都一样,就是在本地开一个ssh tunnel,连通你的海外linux/unix主机和你的电脑。连通海外主机的方式很简单就是登录即可,连同本机的方式是在本机打开一个服务端口(比如3128),你可以通过本机作为代理服务器。

剩下的工作都一样,就是在firefox上装一个autoproxy,然后选择127.0.0.1:服务端口(比如3128)作为代理服务器,然后就可以上网啦。

freebsd,linux,windows的差别在于提供ssh tunnel的方式不同:

1.freebsd 和linux方式一样,且很简单,在shell终端输入ssh [-p remoteport] -D localport -l username host

remoteport :海外主机提供sshd服务的端口(一般是22)

port:本地服务端口

username:海外主机登录用户名

host:海外主机ip

这篇文章对于unix/linux通过ssh翻墙有详细的说明,包括截图:http://blog.totodo.com/archives/122

2.windows提供ssh tunnel的方式

我自己尝试成功的方式主要有两种

(1)通过securtCRT翻墙:详细说明见:http://www.ifunkey.com/1032.html

(2)通过Tunnelier翻墙:详细说明见:http://foxren.com/archives/290

虽然大家说了很多方法,但是每个人都有自己体会,写这篇文章的目的是将自己的体会和经历分享给大家。

Popularity: 53%

共享一本linux经典入门的书《鸟哥的Linux私房菜基础篇

2010年6月2日 1 条评论

linux经典入门的书《鸟哥的Linux私房菜基础篇》,是一本非常好的书,现在提供下载地址(即日起不再提供下载)

2011年4月21日更新:今天发现鸟哥的共享协议,以前我的做法违反了鸟哥的协议。我是非常尊重和敬佩鸟哥的,从即日起,本站不提供《鸟哥的Linux私房菜基础篇》下载,有需要的朋友可以移步到鸟哥的官方网站http://linux.vbird.org/linux_basic/index.php,这裡鸟哥还实时更新,比原来的下载版本更好。

Popularity: 17%

分类: linux 标签:

Shell判断文件,目录是否存在或者具有权限

2010年6月2日 1 条评论

#!/bin/sh

myPath=”/var/log/httpd/”
myFile=”/var /log/httpd/access.log”

#这里的-x 参数判断$myPath是否存在并且是否具有可执行权限
if [ ! -x "$myPath"]; then
mkdir “$myPath”
fi

#这里 的-d 参数判断$myPath是否存在
if [ ! -d "$myPath"]; then
mkdir “$myPath”
fi

#这里的-f参数判断$myFile是否存在
if [ ! -f "$myFile" ]; then
touch “$myFile”
fi

#其他参数还有-n,-n是判断一个变量是否是否有值
if [ ! -n "$myVar" ]; then
echo “$myVar is empty”
exit 0
fi

#两个变量判断是否相等
if [ "$var1" = "$var2" ]; then
echo ‘$var1 eq $var2′
else
echo ‘$var1 not eq $var2′
fi
原文链接:http://www.cublog.cn/u1/42339/showart_1355170.html

Popularity: 12%

分类: linux, shell, unix 标签: ,

linux 实现多台ssh信任 执行命令的操作

2010年6月2日 没有评论

以前发过一篇文章,介绍单台服务器的拷贝,脚本执行scp不用输入密码

其实多台很简单,就是在authorized_keys放入多个rsa_pub信息即可

1. A机上运行:ssh-keygen -t rsa

2. A机上运行:scp /root/.ssh/id_rsa.pub B:/root/.ssh/authorized_keys

3. C机上运行:ssh-keygen -t rsa

4. C机上运行:scp /root/.ssh/id_rsa.pub root@IP:/root/.ssh/   IP     (其中IP是B
机的)

5. 登录到B机,进入/root/.ssh下

6. B机上运行:cat IP >> authorized_keys.

至此,A,C机都可无需密码登录到B机上了, 其他的同样设置

详细信息参见:http://www.zouqingshui.net/headingto3/linux-ssh-command-execute- setting/

Popularity: 11%

分类: linux, unix 标签: ,

脚本执行scp不用输入密码

2010年2月3日 没有评论

有些时候, 我们在复制/移动文件到另一台机器时会用到scp,因为它比较安全。但如果每次都要输入密码,就比较烦了,尤其是在script里。不过,

ssh有另一种用密钥对来验证的方式。下面写出我生成密匙对的过程,供大家参考。

第一步:生成密匙对,我用的是rsa的密钥。 使用命令 “ssh-keygen -t rsa”

代码:

[user1@rh user1]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/user1/.ssh/id_rsa):
Created directory ‘/home/user1/.ssh’.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user1/.ssh/id_rsa.
Your public key has been saved in /home/user1/.ssh/id_rsa.pub.
The key fingerprint is:
e0:f0:3b:d3:0a:3d:da:42:01:6a:61:2f:6c:a0:c6:e7 us@rh.test.com
[user1@rh user1]$

生成的过程中提示输入密钥对保存位置,直接回车,接受默认值就行了。接着会提 示输入一

个不同于你的password的密码,直接回车,让它空着。当然,也可以输入一个。(我比较懒

, 不想每次都要输入密码。) 这样,密钥对就生成完了。

其中公共密钥保存在 ~/.ssh/id_rsa.pub
私有密钥保存在 ~/.ssh/id_rsa

然后改一下 .ssh 目录的权限,使用命令 “chmod 755 ~/.ssh”
代码:

[user1@rh user1]$ chmod 755 ~/.ssh
[user1@rh user1]$

之后把这个密钥对中的公共密钥复制到你要访问的机器上去,并保存为

~/.ssh/authorized_keys.

代码:

[user1@rh user1]$ scp ~/.ssh/id_rsa.pub rh1:/home/user1/.ssh/
authorized_keys
user1@rh1′s password:
id_rsa.pub 100% 228 3.2MB/s 00:00
[user1@rh user1]$

之这 样就大功告成了。之后你再用ssh scp sftp 之类的访问那台机器时,就不用输入密码

了,用在script上更是方 便。

无觅相关文章插件

Popularity: 27%

分类: linux, unix 标签: ,