欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

代码中的无形性能损耗

程序员文章站 2022-05-12 19:07:14
...

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

 

关于我,邯郸人
对这类话题感兴趣?欢迎发送邮件至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
相关标签: 性能