关于vptr

c++中的多态性时靠虚函数来实现的,可以简单地通过一个例子来理解。

class A

{

int a;

public:

virtual void func1(){cout<< "func1:: A"<<endl};

virtual void func2(){cout<< "func2:: A"<<endl};

virtual void func3(){cout<< "func3:: A"<<endl};

}

class B : public A

{

int a;

public:

void func1(){cout<< "func1:: B"<<endl};

void func2(){cout<< "func2:: B"<<endl};

}

void test(A &a)

{

a.func1();

a.func2();

a.func3();

}

int main()

{

A a;

B b;

a.test();

b.test();

return 0;

}

运行结果

func1:: A

func2:: A

func3: A

func1:: B

func2:: B

func3:: A

func1 和 func2在B类中被重载,而func3没有被重载。

编译器时如何找到对应的函数的呢?
在编译时编译器并不知道函数的具体位置,但它插入了一段能找到正确函数体的代码。这种行为被称之为晚捆绑(late binding)运行时捆绑(run-time binding).
编译器通过关键字virtual创建了晚捆绑,它对包含虚函数的类创建了一张表vtable,这张表其实就是一个数组,存储着虚函数的地址,此外还秘密地放置了一个指向vtable的指针vptr。因此像上面的例子sizeof(A)返回应该是8而不是4(32位机器上).
可以通过下面的例子验证这一点
typedef void (*fun)();
void *getp (void* p)
{
return (void*)*(unsigned long*)p;
}
fun getfunc (Base* obj, unsigned long offset)
{
void *vptr = getp(obj);
unsigned char* p = (unsigned char*) vptr;
p += sizeof(void*) * offset;
return (fun)getp(p);
}

int main()

{

A a;

B b;

fun f = getfunc(&a, 0);

(*f)();

f = getfunc(&a, 2);

(*f)();

f = getfunc(&b, 0);

(*f)();

f = getfunc(&b, 2);

(*f)();

}

运行结果

func1:: A

func3: A

func1:: B

func3:: A

Posted in Uncategorized | Leave a comment

转linux 内存中buffer&cache的占用问题

总有很多朋友对于Linux的内存管理有疑问,之前一篇[转]理解Linux的性能日志似乎也没能清除大家的疑虑。而在新版核心中,似乎对这个问题提供了新的解决方法,特转出来给大家参考一下。最后,还附上我对这方法的意见,欢迎各位一同讨论。

当在Linux下频繁存取文件后,物理内存会很快被用光,当程序结束后,内存不会被正常释放,而是一直作为caching。这个问题,貌似有不少人在问,不过都没有看到有什么很好解决的办法。那么我来谈谈这个问题。

一、通常情况
先来说说free命令:

引用
[root@server ~]# free -m
total used free shared buffers cached
Mem: 249 163 86 0 10 94
-/+ buffers/cache: 58 191
Swap: 511 0 511

其中:

引用
total 内存总数
used 已经使用的内存数
free 空闲的内存数
shared 多个进程共享的内存总额
buffers Buffer Cache和cached Page Cache 磁盘缓存的大小
-buffers/cache 的内存数:used - buffers - cached
+buffers/cache 的内存数:free + buffers + cached

可用的memory=free memory+buffers+cached。

有了这个基础后,可以得知,我现在used为163MB,free为86MB,buffer和cached分别为10MB,94MB。
那么我们来看看,如果我执行复制文件,内存会发生什么变化.

引用
[root@server ~]# cp -r /etc ~/test/
[root@server ~]# free -m
total used free shared buffers cached
Mem: 249 244 4 0 8 174
-/+ buffers/cache: 62 187
Swap: 511 0 511

在我命令执行结束后,used为244MB,free为4MB,buffers为8MB,cached为174MB,天呐,都被cached吃掉了。别紧张,这是为了提高文件读取效率的做法。

为了提高磁盘存取效率,Linux做了一些精心的设计,除了对dentry进行缓存(用于VFS,加速文件路径名到inode的转换),还采取了两种主要Cache方式:Buffer Cache和Page Cache。前者针对磁盘块的读写,后者针对文件inode的读写。这些Cache有效缩短了 I/O系统调用(比如read,write,getdents)的时间。

那么有人说过段时间,linux会自动释放掉所用的内存。等待一段时间后,我们使用free再来试试,看看是否有释放?

引用
[root@server test]# free -m
total used free shared buffers cached
Mem: 249 244 5 0 8 174
-/+ buffers/cache: 61 188
Swap: 511 0 511

似乎没有任何变化。(实际情况下,内存的管理还与Swap有关)

那么我能否手动释放掉这些内存呢?回答是可以的!

二、手动释放缓存
/proc是一个虚拟文件系统,我们可以通过对它的读写操作做为与kernel实体间进行通信的一种手段。也就是说可以通过修改/proc中的文件,来对当前kernel的行为做出调整。那么我们可以通过调整/proc/sys/vm/drop_caches来释放内存。操作如下:

引用
[root@server test]# cat /proc/sys/vm/drop_caches
0

首先,/proc/sys/vm/drop_caches的值,默认为0。

引用
[root@server test]# sync

手动执行sync命令(描述:sync 命令运行 sync 子例程。如果必须停止系统,则运行sync 命令以确保文件系统的完整性。sync 命令将所有未写的系统缓冲区写到磁盘中,包含已修改的 i-node、已延迟的块 I/O 和读写映射文件)

引用
[root@server test]# echo 3 > /proc/sys/vm/drop_caches
[root@server test]# cat /proc/sys/vm/drop_caches
3

将/proc/sys/vm/drop_caches值设为3

引用
[root@server test]# free -m
total used free shared buffers cached
Mem: 249 66 182 0 0 11
-/+ buffers/cache: 55 194
Swap: 511 0 511

再来运行free命令,会发现现在的used为66MB,free为182MB,buffers为0MB,cached为11MB。那么有效的释放了buffer和cache。

◎ 有关/proc/sys/vm/drop_caches的用法在下面进行了说明

引用
/proc/sys/vm/drop_caches (since Linux 2.6.16)
Writing to this file causes the kernel to drop clean caches,
dentries and inodes from memory, causing that memory to become
free.

To free pagecache, use echo 1 > /proc/sys/vm/drop_caches; to
free dentries and inodes, use echo 2 > /proc/sys/vm/drop_caches;
to free pagecache, dentries and inodes, use echo 3 >
/proc/sys/vm/drop_caches.

Because this is a non-destructive operation and dirty objects
are not freeable, the user should run sync first.

三、我的意见
上述文章就长期以来很多用户对Linux内存管理方面的疑问,给出了一个比较“直观”的回复,我更觉得有点像是核心开发小组的妥协。
对于是否需要使用这个值,或向用户提及这个值,我是有保留意见的:

引用
1、从man可以看到,这值从2.6.16以后的核心版本才提供,也就是老版的操作系统,如红旗DC 5.0、RHEL 4.x之前的版本都没有;
2、若对于系统内存是否够用的观察,我还是原意去看swap的使用率和si/so两个值的大小;

用户常见的疑问是,为什么free这么小,是否关闭应用后内存没有释放?
但实际上,我们都知道这是因为Linux对内存的管理与Windows不同,free小并不是说内存不够用了,应该看的是free的第二行最后一个值:

引用
-/+ buffers/cache: 58 191

这才是系统可用的内存大小。
实际项目中告诉我们,如果因为是应用有像内存泄露、溢出的问题,从swap的使用情况是可以比较快速可以判断的,但free上面反而比较难查看。
相反,如果在这个时候,我们告诉用户,修改系统的一个值,“可以”释放内存,free就大了。用户会怎么想?不会觉得操作系统“有问题”吗?
所以说,我觉得既然核心是可以快速清空buffer或cache,也不难做到(这从上面的操作中可以明显看到),但核心并没有这样做(默认值是0),我们就不应该随便去改变它。
一般情况下,应用在系统上稳定运行了,free值也会保持在一个稳定值的,虽然看上去可能比较小。
当发生内存不足、应用获取不到可用内存、OOM错误等问题时,还是更应该去分析应用方面的原因,如用户量太大导致内存不足、发生应用内存溢出等情况,否则,清空buffer,强制腾出free的大小,可能只是把问题给暂时屏蔽了。

我觉得,排除内存不足的情况外,除非是在软件开发阶段,需要临时清掉buffer,以判断应用的内存使用情况;或应用已经不再提供支持,即使应用对内存的时候确实有问题,而且无法避免的情况下,才考虑定时清空buffer。(可惜,这样的应用通常都是运行在老的操作系统版本上,上面的操作也解决不了)。O(∩_∩)O哈哈~

Posted in Uncategorized | Leave a comment

(转)Systemtap原理及使用

SystemTap的架构

SystemTap用于检查运行的内核的两种方法是 Kprobes和 返回探针。但是理解任何内核的最关键要素是内核的映射,它提供符号信息(比如函数、变量以及它们的地址)。有了内核映射之后,就可以解决任何符号的地址,以及更改探针的行为。

Kprobes从 2.6.9 版本开始就添加到主流的 Linux 内核中,并且为探测内核提供一般性服务。它提供一些不同的服务,但最重要的两种服务是 Kprobe 和 Kretprobe。Kprobe特定于架构,它在需要检查的指令的第一个字节中插入一个断点指令。当调用该指令时,将执行针对探针的特定处理函数。执行完成之后,接着执行原始的指令(从断点开始)。

Kretprobes有所不同,它操作调用函数的返回结果。注意,因为一个函数可能有多个返回点,所以听起来事情有些复杂。不过,它实际使用一种称为 trampoline的简单技术。您将向函数条目添加一小段代码,而不是检查函数中的每个返回点。这段代码使用 trampoline地址替换堆栈上的返回地址 —— Kretprobe 地址。当该函数存在时,它没有返回到调用方,而是调用 Kretprobe(执行它的功能),然后从 Kretprobe返回到实际的调用方。

图 1展示了 SystemTap 的基本流程,涉及到 3 个交互实用程序和 5 个阶段。该流程首先从 SystemTap 脚本开始。您使用 stap 实用程序将 stap脚本转换成提供探针行为的内核模块。stap 流程从将脚本转换成解析树开始 (pass 1)。然后使用细化(elaboration)步骤 (pass 2)中关于当前运行的内核的符号信息解析符号。接下来,转换流程将解析树转换成 C源代码 (pass 3) 并使用解析后的信息和 tapset脚本(SystemTap 定义的库,包含有用的功能)。stap 的最后步骤是构造使用本地内核模块构建进程的内核模块 (pass 4)。

1. SystemTap流程

有了可用的内核模块之后,stap 完成了自己的任务,并将控制权交给其他两个实用程序SystemTap:staprun和 stapio。这两个实用程序协调工作,负责将模块安装到内核中并将输出发送到 stdout (pass 5)。如果在 shell中按组合键 Ctrl-C 或脚本退出,将执行清除进程,这将导致卸载模块并退出所有相关的实用程序。

SystemTap 的一个有趣特性是缓存脚本转换的能力。如果安装后的脚本没有更改,您可以使用现有的模块,而不是重新构建模块。图 2显示了 user-space 和 kernel-space元素以及基于 stap 的转换流程。

图 2.从 kernel/user-space 角度了解 SystemTap流程

3 Systemtap工作原理

tapsets是一个脚本库,包含了许多tapset,每一个tapset一般为某一内核子系统或特定的功能块预定义了一套探测点、辅助函数或全局变量供用户脚本或其它的tapset引用,它定义的一些数据能够被每一个探测点处理函数或脚本使用,这些数据通常通过使用处理函数语句块(HSB Handler Statement Block)来出口,HSB语句块中的变量就是被出口的数据。tapset一般由该内核子系统的开发者或对子系统非常了解的开发者编写,既使用了脚本语言,也使用了C语言,并且它已经被测试和验证,可以安全使用。tapsets属于Systemtap发行包的一部分。

Systemtap实现了一个脚本转换器/翻译器,当用户执行一个Systemtap脚本时,Systemtap将首先对它进行分析和一些安全检查,如果它引用了Systemtap预定义的脚本库提供的函数,Systemtap也将读取脚本库得到相应的代码,对于一些内核变量或符号的引用,它必须根据内核调试信息来解析到相应的地址。然后,它被转换成C代码,在这个转换中,Systemtap将根据需要增加必要的锁和安全检查代码。探测点之间共享的变量将被转换成恰当的静态声明并有锁保护,每组本地变量被转换到一个合成的调用帧结构中以避免消耗内核的栈空间。关联到探测点的处理函数被封装成一个接口函数,那调用恰当的kprobe接口函数来注册该探测点。

产生的C代码包含了一些对运行时tapset的引用,运行时tapset库提供了许多Systemtap接口函数,如通用的查询表、受限内存管理、启动、关闭、I/O操作以及其它一些函数。生成的C代码编译链接之后生成一个可加载的内核模块。为了快速得到运行结果,Systemtap使用了relayfs,当加载生成的内核模块后,该模块的初始化函数初始化自身,然后调用kprobe接口函数注册脚本中定义的探测点。当内核运行到注册的探测点时,相应的处理函数被调用,用户在处理函数中的输出语句将调用relayfs接口函数输出结果数据,用户在处理函数也可以调用一些内核的性能测量函数。当用户主动停止或脚本设定的条件满足时,模块将调用退出函数卸载已经注册的探测点并做一些清理处理就卸载模块自身。

Systemtap在运行时启动了一个进程,它专门负责通过relayfs读去模块的输出数据并即时地输出给用户。(注:要probe的代码必须有调试信息,可以查看探测点的上下文变量)

SystemTap实用实例

监控函数的性能

#show exec time of function(@2) and the tid who execute it

global t, call_time

probe process(@1).function(@2).call

{

t = gettimeofday_ns();

}

probe process(@1).function(@2).return

{

call_time <<< gettimeofday_ns()-t;

}

probe timer.s(1)

{

if(@count(call_time)>0)

{

printf("avg time %d total :%d/n", @avg(call_time), @count(call_time));

delete call_time;

}

else

{

println("no call");

}

}

probe begin

{

println("Ready");

}

该脚本用于测试由参数传递的函数运行时所占用的时间,即每秒打印一次平均执行时间,以及调用次数。通过这样一个脚本可以大概的确定我们要probe的函数的性能以及它相对于线程的使用时间。“<<<”表示数组操作,把上面的function改为statement,可probe行范围。@avg(call_time)计算数组内所有元素和的平均值,count(call_time)计算数组元素个数。

监控所有的系统调用

global syscalllist

probe begin {

printf("System Call Monitoring Started (10 seconds).../n")

}

probe syscall.*

{

syscalllist[pid(), execname()]++

}

probe timer.ms(10000) {

foreach ( [pid, procname] in syscalllist ) {

printf("%s[%d] = %d/n", procname, pid, syscalllist[pid, procname] )

}

exit()

}

统计10s内的所有系统调用及次数。

监控某个程序的所有系统调用

global syscalllist

probe begin {

printf("Syslog Monitoring Started (10 seconds).../n")

}

probe syscall.*

{

if (execname() == @1) {

syscalllist[name]++

}

}

probe timer.ms(10000) {

foreach ( name in syscalllist ) {

printf("%s = %d/n", name, syscalllist[name] )

}

printf("------------------------/n");

}

收集网络包

global recv, xmit

probe begin {

printf("Starting network capture (Ctl-C to end)/n")

}

probe netdev.receive {

recv[dev_name, pid(), execname()] <<< length

}

probe netdev.transmit {

xmit[dev_name, pid(), execname()] <<< length

}

probe end {

printf("/nEnd Capture/n/n")

printf("Iface Process........ PID.. RcvPktCnt XmtPktCnt/n")

foreach ([dev, pid, name] in recv) {

recvcount = @count(recv[dev, pid, name])

xmitcount = @count(xmit[dev, pid, name])

printf( "%5s %-15s %-5d %9d %9d/n", dev, name, pid, recvcount, xmitcount )

}

delete recv

delete xmit

}

count计算某个进程接收和发送的报文数,通过avg可计算收到(发送)的报文平均长度,sum可计算收到(发送)的报文的总长度。该收集的数据与dstat有点相似,但它又能够指出具体的进程使用情况,比dstat要详细些。

监听某个signal:sig_send.stp

probe signal.send{
if (sig_name == "SIGKILL")
printf("%s was send to %s(pid:%d) by %s uid:%d", sig_name, pid_name, sig_pid, execname(),uid())
}

$stap -L signal.send

$sudo stap sig_send.stp

监测某个函数的某个区间执行情况(行),对于行经常出现行地址错误,所以多调整一下用-L单独测试

probe process(@1).statement(@2)
{
num++;
t = gettimeofday_ns();
}
probe process(@1).statement(@3)
{
call_time = gettimeofday_ns()-t;
printf("\n%s exec time:%d", @3,call_time);
}

sudo stap insline.stp "libexec/mysqld" "*@/home/xiangzhong.wxd/mysql-5.1.48/sql/sql_select.cc:11388" "*@/home/xiangzhong.wxd/mysql-5.1.48/sql/sql_select.cc:11391"

通过使用-L可以测试某条语句是否是正确的:

sudo stap -L 'process("/usr/local/mysql/libexec/mysqld").function("apply_event")'

sudo stap -L 'process("libexec/mysqld").statement("*@/home/xiangzhong.wxd/mysql-5.1.48/sql/sql_select.cc:11388")'

from http://blog.csdn.net/wudongxu/article/details/6345481

参考:

http://www.ibm.com/developerworks/cn/linux/l-systemtap/

http://www.ibm.com/developerworks/cn/linux/l-cn-systemtap3/

Posted in Uncategorized | Leave a comment

ubuntu 安装iasp

1.  安装apache2 apt-get install apache2

2. 安装iasp

tar zxvf iASP2.1.01.tar.gz.

/install.sh

欢迎画面过后提示输入JDK路径,输入/usr/jdk1.5;提示输入IASP的安装路径,输入:/usr/local/iasp;如果该目录不存在会提示创建该目录,回答:Y;之后会问是否现在配置WEB服务器,回答 Y;2、选择代理服务器,这里是指Instant ASP和Apache通信的代理服务器,输入1选择 instant asp native servlet support3、选择WEB服务器;输入2选择Apache;4、选择服务器版本,输入11选择1.3.2X5、输入Apache配置文件路径,输入/usr/local/apache/conf6、输入代理服务器地址,可以默认127.0.0.1,也可以指定Apache绑定的地址;7、输入代理服务器端口,Instant ASP与Apache 交互的端口,默认为9098,可以不做修改;8、输入WEB管理端口,可默认9095;安装完成。打开httpd.conf 可以发现Instant ASP在末尾增加了如下几行:# iASP SettingLoadModule iasp_module "/usr/local/iasp/iasp21/bin/apache/linux/1.3.20/mod_iasp.so"                                                                           Alias /iasp "/usr/local/iasp/iasp21"IaspConfig server "/usr/local/iasp/iasp21/properties/server.properties"IaspConfig rules "/usr/local/iasp/iasp21/properties/rules.properties"

3. 重启apache

apachectl restart

报错  Cannot load /usr/local/iasp21/bin/apache/linux/2.0/mod_iasp.so into server

解决办法:安装编译工具包apache2-prefork-dev

apt-get install apache2-prefork-dev

cd /usr/local/iasp21/bin/apache/source/2.0
重新执行“
apxs2 -i -c *.c

重启apache仍然报错

这是因为iasp2.11发布的时候apache最高版本是2.0.x. 而2.0和2.2是两个不同的开发分支有很多不同。2.0里面的mod和apr API多数不一样。

下载更新包

http://download.csdn.net/source/2804948

覆盖/usr/local/iasp21/bin/apache/source/2.0这个目录的代码,重新编译。

成功!

测试一下

vi test.asp

<html>

<head>
<title>Test iASP</title>
</head>

<body>
<%
Response.Write "<BR><h1>Congradulations!<BR>Instant ASP has worked for you!</h1>"
%>
</body>
</html>

浏览器输入 http://www.laocius.com/test.asp

Congradulations!
Instant ASP has worked for you!

完工!

参考 http://www.php318.com/show_60.html

http://zhaoyong.blog.51cto.com/61971/82305

Posted in Uncategorized | Leave a comment

设置google不调转 www.google.co.jp

由于我的vps在东京,所以浏览器输入www.google.com时会自动跳转到www.google.co.jp.如果想让浏览器不调转。输入www.google.com/ncr. 这样以后google.com 就是google.com, 不会乱跳转了。

Posted in Uncategorized | Leave a comment

testdisk 恢复移动硬盘分区

自从把ubuntu11.04升级到11.10后,wifi就连不上了,原因可能是加密验证方式问题,因为仍然可以连接没有加密到wifi。一直也没有深究原因(工作后已经不像以前那样有精力折腾了),后来就决定重装11.04算了,于是选了个11.04对应的linux mint装了上去。另外还有两个分别为10G和4G的分区,以前瞎折腾时留着装别的系统和作引导备份用的,这次索性合并了挂在到linux下。但第二天发现windows突然进不去了。话说windows还是必须的,因为支付宝以及各大银行还是不给力。接下来没有经过过多思考我就做了一个非常危险的操作:拿winPE进去用硬盘工具做了一下检测修复。这一下完了,等我重启机器的时候,什么都没了!!再次用winPE进去,发现只有最初的一个10GB分区了,就是当初10与4合并的那个。拿ubuntu光盘启动进去查看,也只有一个分区。于是一不做二不休,直接格了整块硬盘重装了ubuntu11.10。除了几张照片和一些聊天记录,硬盘里没有什么重要的东西。以前一直像这样来一个痛快的,可还是舍不得垃圾的windows。

第二天才发现,我的移动硬盘分区也出现了同样的情况。只剩了一个分区。似乎NTFS受到偏见,两次发现都是只剩一个fat32分区。移动硬盘里还是有些重要东西的。还是像恢复一下。但以前只在windows下用过file recovery。现在没了windows,只能想别的办法了,google了一下,第一个就找到了testdisk。命令行模式的,方便好用,几步就恢复了原来的分区,看一下,原来的文件全都在。

testdisk 请参考http://www.cgsecurity.org/wiki/TestDisk_Step_By_Step http://www.cgsecurity.org/wiki/TestDisk_Step_By_Step

Posted in Uncategorized | Leave a comment

健身体验

算起来到今天为止,健身已经有差不多四个月了,效果还是有的,但不够,胸肌和腹肌还勉强满意(这种要有多年做俯卧撑到底子),但肩部和背部就不行了。看来,不论干什么都需要全身心的投入,都需要讲究正确的方法。

健身的前两个月,基本上是瞎练。感觉健身房里的东西都很新鲜,一会儿抓起这个拉两下,一会儿又到那边推两下。一周有时去三次,有时去两次,有时甚至只一次。饮食也维持原来的样子。现在想想,那样要能练出身材才怪呢。

最初去健身房的目地只是减肥。那时大多是游游泳而已,后来就觉得游泳运动量不够,想游出身材来很难。那时饮食控制也很严格,早餐两个饼一个鸡蛋,有时不吃,午餐正常,晚餐3~5两猪肉加一个馒头,周末经常一整天不吃。减肥的效果也是明显的,一个月剪了近10斤吧。

但是控制饮食却不是建很爽的事,这与我一直向往自由的理念也不符。还是要增大运动量。后来偶尔在网上看到本书《the truth about 6 pack abs》。书中谈到一个理论让我兴奋不已:肌肉含量越高,代谢率就越高。也就是说只要肌肉含量足够高,代谢率就高,睡觉比常人消耗的能量也高,那么就可以想吃什么就吃什么而不用担心体重了。这个理论后来得到多方证实。从那时期,每周去三次健身房,一直到现在。

关于蛋白粉,刚开始总持怀疑态度。觉得还是吃自然的东西好。但后来经过别人的推荐还是买了桶BSN。就像一位教练所说的那样:protein powder is just like your cell phones , TV, etc. Do you really need these. the answer is no. 'cause for thousands of years people have been living without them. it's the same with protein with protein powder. Do you really need protein powder? No. But just like like cell phones TVs, cars that can make our lives more convenient, protein powder can make our workouts easier.

另一个最近发现的兴奋不已的理论是超量补偿原理 或超量恢复原理。肌肉或者肌群在适当运动练习之后,会使肌肉产生适度的疲劳和形态功能等等方面一定程度的下降。通过适当时间的休息,可以使肌肉的力量和形态功能等方面恢复到运动前的水平,并且在一定时间之内,还可以继续上升并且超过原有水平。随休息的时间延长,又逐渐下降回原有的功能水平。如果下一次练习是在超量恢复(肌肉功能上升并超过原有水平的一段时间内)的阶段进行的,就可以保持超量恢复不会消退,并且能逐步积累练习效果。如此通过反复的肌力练习就可以使肌肉体积增大,肌肉力量增强。这就是“超量恢复”。

像这些健身的基本常识、理论,如果一开始就知道该多好。

对健身的另一个体会就是中国在健身方面远远落后与其他国家。在国外很多健身房都配备专业的营养师,在国内我只知道国家队有运动营养师。另外,我们健身房太少,健身的人也太少,即便在北京这样的大城市,健身也不是很普及。

Posted in Uncategorized | Leave a comment

鼠标拖动 在vnc中输入CTRL-C

记得以前遇到过拖动鼠标就输入CTRL-C的情况。今天同事又遇到同样问题,但却想不起来当时怎么解决的了,google了一下,找到了提示,原来是因为垃圾有道词典的问题。

解决办法:关闭有道词典屏幕取词功能。

Posted in hack | Leave a comment

vi dos format to unix format

windows下编辑的文件在unix下用vi打开的话,在每行结尾会会出现^M,但用vim打开就不会出现这种现象这是因为windows下的文本每行有两个结束符'\r\n'(回车、换行),而在unix只有一个'\n'。

解决办法 :%s/^M//g

'^M'输入方法:CTRL + V  + M

也试过 ':set fileformat=unix' 不管用,不知道为什么。

Posted in Uncategorized | Leave a comment

64TB虚拟内存

80386 每个任务最多可以有16384(2的14次方)个段,每个段可长达4GB,所以一个任务的逻辑地址空间为64TB(2的46次方)。这里16384是如何来的?

因为每个任务最多有16384个描述符,即8192+8192,8192(2的13次方)为全局描述符表和局部描述符表的最大长度。

Posted in hack | Leave a comment