`
donlianli
  • 浏览: 336407 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Group-logo
Elasticsearch...
浏览量:216631
社区版块
存档分类
最新评论

代码中的无形性能损耗

阅读更多

最近研究了代码底层的一些实现机制,发现很多“真相”,总结了一下,形成本文。下面有点瞎扯(扯完我也不知道要给大家强调什么)如有不同意见,欢迎大家拍砖。

 

关于我,邯郸人
对这类话题感兴趣?欢迎发送邮件至donlianli@126.com
请支持原创http://donlianli.iteye.com/blog/2156656
 

1、编程语言本身带来的损耗

Java语言编写的程序(class文件),程序需要首先运行java虚拟机(先运行java.exe,建立java虚拟机,加载、验证、准备、解析和初始化class等一系列步骤),然后才能运行你的main方法。

同样.net平台运行的程序也一样,另外新兴的ruby,Scala等也是运行在Java虚拟机上面的,所以肯定也存在这样的问题。

 

这些语言还有另外一个问题,就是这些语言属于解释性语言。尽管有git技术的加速,但仍然逃脱不了其天生的劣势。运行速度和编译性语言相比,还是差不少的。尤其是像JS(Javascript)中这种语言,单线程执行,当一个网页包含的js过多时,会出现客户端无响应的问题。这种情况直到出现chrome浏览器和IE8之后,问题才得到缓解。

 

2、语言本身插入的"通用代码"

下面几行简单的c代码

int main(void){

    return 0;

}

编译成可执行文件(linux64 OS)后,竟然多出12个函数代码(需要查看汇编指令)。也就是说为了运行你的一句return 0,系统需要在你的代码前和代码后面执行多达12次调用。

其实这种情况很普遍,我就拿我很熟悉的Java语言为例,为了支持gcjvm需要在你的Java代码中种植很多安全点,以方便在gc时,各个线程在安全点停止下来(线程是主动停止下来等待gc)。这些安全点都是语言在你的代码中插入的无形损耗。为了让同步的变量可见,Java会在某些代码中间插入CyclicBarrier,让多个需要立即可见的变量互相等待一下,然后让cpu将变量刷回主存。

 

3、可执行程序加载

所有的程序都会有这个问题,不可避免。原因是所有程序都在OS的管理下运行的,除非你的程序就是操作系统。

在程序开始运行前,OS要做以下工作:

  • 创建进程PCB(进程属于新建态),
  • exe文件加载到内存
  • 映射虚拟内存,分配页表,设置MMU
  • 操作系统为程序运行分配必须的资源(如输入输出文件等).

通常,因此这种损耗基本上可以忽略。

 

4、模式切换

OS调度来说一般有线程切换和进程切换,现在的OS一般是以线程为单位进行调度,无论是线程切换还是进程切换,都会引起用户模式和内核模式的切换。因此线程切换,虽然损耗比较小,但当线程的数量非常多的时候,其损耗也是不可忽略的。

线程切换需要进行的工作:

step 1. 保存被中断(一般上下文切换都是由中断引起的,比如说时间片用完)线程ACPU相关寄存器。

step 2. 保存现程控制块(TCB)相关信息,标志现程当前状态(如果是时间片用完,则属于就绪态)

step 3. 根据当前线程的状态,将其放入相关队列(假如是时间片用完,则放入就绪队列)

step 4. 从就绪队列选择另外一个线程B(可能会有一个算法在这里面,因为队列有很多就绪线程,怎么选)

step 5. 修改线程B的线程控制块(TCB),标记其为运行态。

step 6. 恢复线程BCPU现场

 

我们的代码中,如果需要大量的io时,这时你要注意了,通常每次调用io函数,都会发生内核模式和用户模式切换。这种切换速度是非常快的,但一般的处理器也有硬件支持。

用户模式切内核模式进行的工作

step1 根据线程(进程)状态,将线程放到挂起队列末尾。

step2 保存用户的CPU的寄存器现场

step2 按照io号去处理。。。。(这个可能会很长)

linux中,可以通过vmstat cscontext switch)列看到上下文切换的次数

5、函数调用

其实我们的程序入口都是从一个main函数开始,然后就是一层又一层的函数调用,这个是不可避免的。这方面的损耗也比较小。其主要损耗在于调用参数及现场保护。

当调用一个参数时,需要进行以下一些列工作

  • 参数入栈(将函数调用的参数压入函数栈,参数越多,耗时越长)
  • 跳转地址(跳转前还需要保护当前代码地址)
  • 函数调用
  • 函数调用完毕,逆过程(回跳至调用者代码,释放之前入栈参数空间)

64位系统,AMD对函数堆栈稍微做了些改变,当函数参数正数不超过6个,浮点数参数不超过8个时,可以将参数直接存放在寄存器中,不用再将参数进行入栈。但这个优化似乎不起太大作用,因为一旦函数调用超过2层,同样还需要将参数入栈。

从上面的过程,函数参数有个入栈工程,通常函数的内的局部变量也在函数站内。一般这个栈的大小是有限制的(Java中默认是512k)。如果你的函数调用太深或者你的函数出现了死循环,cpu就会不断的往函数栈中push参数,直到这个栈满了,就出现了stack overflow的异常。

 

6os与用户程序之间的数据传递损耗

比如用户需要读取一个配置文件,首先,文件数据到达操作系统的缓冲区,然后,再传递给用户的目的缓存区(至于为什么这么做,大家可以看看Java nio编程),甚至有时候,我们代码传递到用户缓存区,还没有到达正确的位置,可能还要转换成某个对象,存放到共享数据区。



 


<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->

总结:记得有人说过这样的话,通用即难用。现在想想是有一定道理的,上面的每一种损耗,都是为了让我们的语言更优雅,或者为了降低我们编程的难度而采取的措施。我老觉得苹果手机比android手机快,可能很大一部分原因是android采用的Java引起。尽管上面所述有些损耗都非常小,以至于我们根本无法察觉。但只要执行指令就会耗电,而且冗余指令越多,耗电量越大。

 

参考资料

http://www.cnblogs.com/ktgu/p/3529144.html

 http://baike.baidu.com/view/1760224.htm

 

 附:c代码反编译后代码

0000000000400358 <_init>:
  400358:	48 83 ec 08          	sub    $0x8,%rsp
  40035c:	e8 5b 00 00 00       	callq  4003bc <call_gmon_start>
  400361:	e8 ea 00 00 00       	callq  400450 <frame_dummy>
  400366:	e8 b5 01 00 00       	callq  400520 <__do_global_ctors_aux>
  40036b:	48 83 c4 08          	add    $0x8,%rsp
  40036f:	c3                   	retq   

Disassembly of section .plt:

0000000000400370 <__libc_start_main@plt-0x10>:
  400370:	ff 35 72 04 20 00    	pushq  0x200472(%rip)        # 6007e8 <_GLOBAL_OFFSET_TABLE_+0x8>
  400376:	ff 25 74 04 20 00    	jmpq   *0x200474(%rip)        # 6007f0 <_GLOBAL_OFFSET_TABLE_+0x10>
  40037c:	0f 1f 40 00          	nopl   0x0(%rax)

0000000000400380 <__libc_start_main@plt>:
  400380:	ff 25 72 04 20 00    	jmpq   *0x200472(%rip)        # 6007f8 <_GLOBAL_OFFSET_TABLE_+0x18>
  400386:	68 00 00 00 00       	pushq  $0x0
  40038b:	e9 e0 ff ff ff       	jmpq   400370 <_init+0x18>

Disassembly of section .text:

0000000000400390 <_start>:
  400390:	31 ed                	xor    %ebp,%ebp
  400392:	49 89 d1             	mov    %rdx,%r9
  400395:	5e                   	pop    %rsi
  400396:	48 89 e2             	mov    %rsp,%rdx
  400399:	48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
  40039d:	50                   	push   %rax
  40039e:	54                   	push   %rsp
  40039f:	49 c7 c0 80 04 40 00 	mov    $0x400480,%r8
  4003a6:	48 c7 c1 90 04 40 00 	mov    $0x400490,%rcx
  4003ad:	48 c7 c7 74 04 40 00 	mov    $0x400474,%rdi
  4003b4:	e8 c7 ff ff ff       	callq  400380 <__libc_start_main@plt>
  4003b9:	f4                   	hlt    
  4003ba:	90                   	nop
  4003bb:	90                   	nop

00000000004003bc <call_gmon_start>:
  4003bc:	48 83 ec 08          	sub    $0x8,%rsp
  4003c0:	48 8b 05 11 04 20 00 	mov    0x200411(%rip),%rax        # 6007d8 <_DYNAMIC+0x190>
  4003c7:	48 85 c0             	test   %rax,%rax
  4003ca:	74 02                	je     4003ce <call_gmon_start+0x12>
  4003cc:	ff d0                	callq  *%rax
  4003ce:	48 83 c4 08          	add    $0x8,%rsp
  4003d2:	c3                   	retq   
  4003d3:	90                   	nop
  4003d4:	90                   	nop
  4003d5:	90                   	nop
  4003d6:	90                   	nop
  4003d7:	90                   	nop
  4003d8:	90                   	nop
  4003d9:	90                   	nop
  4003da:	90                   	nop
  4003db:	90                   	nop
  4003dc:	90                   	nop
  4003dd:	90                   	nop
  4003de:	90                   	nop
  4003df:	90                   	nop

00000000004003e0 <__do_global_dtors_aux>:
  4003e0:	55                   	push   %rbp
  4003e1:	48 89 e5             	mov    %rsp,%rbp
  4003e4:	53                   	push   %rbx
  4003e5:	48 83 ec 08          	sub    $0x8,%rsp
  4003e9:	80 3d 18 04 20 00 00 	cmpb   $0x0,0x200418(%rip)        # 600808 <completed.6349>
  4003f0:	75 4b                	jne    40043d <__do_global_dtors_aux+0x5d>
  4003f2:	bb 38 06 60 00       	mov    $0x600638,%ebx
  4003f7:	48 8b 05 12 04 20 00 	mov    0x200412(%rip),%rax        # 600810 <dtor_idx.6351>
  4003fe:	48 81 eb 30 06 60 00 	sub    $0x600630,%rbx
  400405:	48 c1 fb 03          	sar    $0x3,%rbx
  400409:	48 83 eb 01          	sub    $0x1,%rbx
  40040d:	48 39 d8             	cmp    %rbx,%rax
  400410:	73 24                	jae    400436 <__do_global_dtors_aux+0x56>
  400412:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)
  400418:	48 83 c0 01          	add    $0x1,%rax
  40041c:	48 89 05 ed 03 20 00 	mov    %rax,0x2003ed(%rip)        # 600810 <dtor_idx.6351>
  400423:	ff 14 c5 30 06 60 00 	callq  *0x600630(,%rax,8)
  40042a:	48 8b 05 df 03 20 00 	mov    0x2003df(%rip),%rax        # 600810 <dtor_idx.6351>
  400431:	48 39 d8             	cmp    %rbx,%rax
  400434:	72 e2                	jb     400418 <__do_global_dtors_aux+0x38>
  400436:	c6 05 cb 03 20 00 01 	movb   $0x1,0x2003cb(%rip)        # 600808 <completed.6349>
  40043d:	48 83 c4 08          	add    $0x8,%rsp
  400441:	5b                   	pop    %rbx
  400442:	c9                   	leaveq 
  400443:	c3                   	retq   
  400444:	66 66 66 2e 0f 1f 84 	data32 data32 nopw %cs:0x0(%rax,%rax,1)
  40044b:	00 00 00 00 00 

0000000000400450 <frame_dummy>:
  400450:	48 83 3d e8 01 20 00 	cmpq   $0x0,0x2001e8(%rip)        # 600640 <__JCR_END__>
  400457:	00 
  400458:	55                   	push   %rbp
  400459:	48 89 e5             	mov    %rsp,%rbp
  40045c:	74 12                	je     400470 <frame_dummy+0x20>
  40045e:	b8 00 00 00 00       	mov    $0x0,%eax
  400463:	48 85 c0             	test   %rax,%rax
  400466:	74 08                	je     400470 <frame_dummy+0x20>
  400468:	bf 40 06 60 00       	mov    $0x600640,%edi
  40046d:	c9                   	leaveq 
  40046e:	ff e0                	jmpq   *%rax
  400470:	c9                   	leaveq 
  400471:	c3                   	retq   
  400472:	90                   	nop
  400473:	90                   	nop

0000000000400474 <main>:
  400474:	55                   	push   %rbp
  400475:	48 89 e5             	mov    %rsp,%rbp
  400478:	b8 00 00 00 00       	mov    $0x0,%eax
  40047d:	c9                   	leaveq 
  40047e:	c3                   	retq   
  40047f:	90                   	nop

0000000000400480 <__libc_csu_fini>:
  400480:	f3 c3                	repz retq 
  400482:	66 66 66 66 66 2e 0f 	data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
  400489:	1f 84 00 00 00 00 00 

0000000000400490 <__libc_csu_init>:
  400490:	48 89 6c 24 d8       	mov    %rbp,-0x28(%rsp)
  400495:	4c 89 64 24 e0       	mov    %r12,-0x20(%rsp)
  40049a:	48 8d 2d 7b 01 20 00 	lea    0x20017b(%rip),%rbp        # 60061c <__init_array_end>
  4004a1:	4c 8d 25 74 01 20 00 	lea    0x200174(%rip),%r12        # 60061c <__init_array_end>
  4004a8:	4c 89 6c 24 e8       	mov    %r13,-0x18(%rsp)
  4004ad:	4c 89 74 24 f0       	mov    %r14,-0x10(%rsp)
  4004b2:	4c 89 7c 24 f8       	mov    %r15,-0x8(%rsp)
  4004b7:	48 89 5c 24 d0       	mov    %rbx,-0x30(%rsp)
  4004bc:	48 83 ec 38          	sub    $0x38,%rsp
  4004c0:	4c 29 e5             	sub    %r12,%rbp
  4004c3:	41 89 fd             	mov    %edi,%r13d
  4004c6:	49 89 f6             	mov    %rsi,%r14
  4004c9:	48 c1 fd 03          	sar    $0x3,%rbp
  4004cd:	49 89 d7             	mov    %rdx,%r15
  4004d0:	e8 83 fe ff ff       	callq  400358 <_init>
  4004d5:	48 85 ed             	test   %rbp,%rbp
  4004d8:	74 1c                	je     4004f6 <__libc_csu_init+0x66>
  4004da:	31 db                	xor    %ebx,%ebx
  4004dc:	0f 1f 40 00          	nopl   0x0(%rax)
  4004e0:	4c 89 fa             	mov    %r15,%rdx
  4004e3:	4c 89 f6             	mov    %r14,%rsi
  4004e6:	44 89 ef             	mov    %r13d,%edi
  4004e9:	41 ff 14 dc          	callq  *(%r12,%rbx,8)
  4004ed:	48 83 c3 01          	add    $0x1,%rbx
  4004f1:	48 39 eb             	cmp    %rbp,%rbx
  4004f4:	72 ea                	jb     4004e0 <__libc_csu_init+0x50>
  4004f6:	48 8b 5c 24 08       	mov    0x8(%rsp),%rbx
  4004fb:	48 8b 6c 24 10       	mov    0x10(%rsp),%rbp
  400500:	4c 8b 64 24 18       	mov    0x18(%rsp),%r12
  400505:	4c 8b 6c 24 20       	mov    0x20(%rsp),%r13
  40050a:	4c 8b 74 24 28       	mov    0x28(%rsp),%r14
  40050f:	4c 8b 7c 24 30       	mov    0x30(%rsp),%r15
  400514:	48 83 c4 38          	add    $0x38,%rsp
  400518:	c3                   	retq   
  400519:	90                   	nop
  40051a:	90                   	nop
  40051b:	90                   	nop
  40051c:	90                   	nop
  40051d:	90                   	nop
  40051e:	90                   	nop
  40051f:	90                   	nop

0000000000400520 <__do_global_ctors_aux>:
  400520:	55                   	push   %rbp
  400521:	48 89 e5             	mov    %rsp,%rbp
  400524:	53                   	push   %rbx
  400525:	48 83 ec 08          	sub    $0x8,%rsp
  400529:	48 8b 05 f0 00 20 00 	mov    0x2000f0(%rip),%rax        # 600620 <__CTOR_LIST__>
  400530:	48 83 f8 ff          	cmp    $0xffffffffffffffff,%rax
  400534:	74 19                	je     40054f <__do_global_ctors_aux+0x2f>
  400536:	bb 20 06 60 00       	mov    $0x600620,%ebx
  40053b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)
  400540:	48 83 eb 08          	sub    $0x8,%rbx
  400544:	ff d0                	callq  *%rax
  400546:	48 8b 03             	mov    (%rbx),%rax
  400549:	48 83 f8 ff          	cmp    $0xffffffffffffffff,%rax
  40054d:	75 f1                	jne    400540 <__do_global_ctors_aux+0x20>
  40054f:	48 83 c4 08          	add    $0x8,%rsp
  400553:	5b                   	pop    %rbx
  400554:	c9                   	leaveq 
  400555:	c3                   	retq   
  400556:	90                   	nop
  400557:	90                   	nop

Disassembly of section .fini:

0000000000400558 <_fini>:
  400558:	48 83 ec 08          	sub    $0x8,%rsp
  40055c:	e8 7f fe ff ff       	callq  4003e0 <__do_global_dtors_aux>
  400561:	48 83 c4 08          	add    $0x8,%rsp
  400565:	c3                   	retq   

 

 

 

 

 

 

 

  • 大小: 8.2 KB
1
1
分享到:
评论
2 楼 dieslrae 2014-11-17  
and so?
1 楼 freezingsky 2014-11-16  
有什么建议?

相关推荐

Global site tag (gtag.js) - Google Analytics