最近研究了代码底层的一些实现机制,发现很多“真相”,总结了一下,形成本文。下面有点瞎扯(扯完我也不知道要给大家强调什么)如有不同意见,欢迎大家拍砖。
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语言为例,为了支持gc,jvm需要在你的Java代码中种植很多安全点,以方便在gc时,各个线程在安全点停止下来(线程是主动停止下来等待gc)。这些安全点都是语言在你的代码中插入的无形损耗。为了让同步的变量可见,Java会在某些代码中间插入CyclicBarrier,让多个需要立即可见的变量互相等待一下,然后让cpu将变量刷回主存。
3、可执行程序加载
所有的程序都会有这个问题,不可避免。原因是所有程序都在OS的管理下运行的,除非你的程序就是操作系统。
在程序开始运行前,OS要做以下工作:
- 创建进程PCB(进程属于新建态),
- 将exe文件加载到内存
- 映射虚拟内存,分配页表,设置MMU
- 操作系统为程序运行分配必须的资源(如输入输出文件等).
通常,因此这种损耗基本上可以忽略。
4、模式切换
从OS调度来说一般有线程切换和进程切换,现在的OS一般是以线程为单位进行调度,无论是线程切换还是进程切换,都会引起用户模式和内核模式的切换。因此线程切换,虽然损耗比较小,但当线程的数量非常多的时候,其损耗也是不可忽略的。
线程切换需要进行的工作:
step 1. 保存被中断(一般上下文切换都是由中断引起的,比如说时间片用完)线程A的CPU相关寄存器。
step 2. 保存现程控制块(TCB)相关信息,标志现程当前状态(如果是时间片用完,则属于就绪态)
step 3. 根据当前线程的状态,将其放入相关队列(假如是时间片用完,则放入就绪队列)
step 4. 从就绪队列选择另外一个线程B(可能会有一个算法在这里面,因为队列有很多就绪线程,怎么选)
step 5. 修改线程B的线程控制块(TCB),标记其为运行态。
step 6. 恢复线程B的CPU现场
我们的代码中,如果需要大量的io时,这时你要注意了,通常每次调用io函数,都会发生内核模式和用户模式切换。这种切换速度是非常快的,但一般的处理器也有硬件支持。
用户模式切内核模式进行的工作
step1 根据线程(进程)状态,将线程放到挂起队列末尾。
step2 保存用户的CPU的寄存器现场
step2 按照io号去处理。。。。(这个可能会很长)
在linux中,可以通过vmstat 的cs(context switch)列看到上下文切换的次数
5、函数调用
其实我们的程序入口都是从一个main函数开始,然后就是一层又一层的函数调用,这个是不可避免的。这方面的损耗也比较小。其主要损耗在于调用参数及现场保护。
当调用一个参数时,需要进行以下一些列工作
- 参数入栈(将函数调用的参数压入函数栈,参数越多,耗时越长)
- 跳转地址(跳转前还需要保护当前代码地址)
- 函数调用
- 函数调用完毕,逆过程(回跳至调用者代码,释放之前入栈参数空间)
在64位系统,AMD对函数堆栈稍微做了些改变,当函数参数正数不超过6个,浮点数参数不超过8个时,可以将参数直接存放在寄存器中,不用再将参数进行入栈。但这个优化似乎不起太大作用,因为一旦函数调用超过2层,同样还需要将参数入栈。
从上面的过程,函数参数有个入栈工程,通常函数的内的局部变量也在函数站内。一般这个栈的大小是有限制的(Java中默认是512k)。如果你的函数调用太深或者你的函数出现了死循环,cpu就会不断的往函数栈中push参数,直到这个栈满了,就出现了stack overflow的异常。
6、os与用户程序之间的数据传递损耗
比如用户需要读取一个配置文件,首先,文件数据到达操作系统的缓冲区,然后,再传递给用户的目的缓存区(至于为什么这么做,大家可以看看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
相关推荐
这涉及到多个方面的检查,包括汽车的有形损耗和无形损耗的判断。有形损耗指的是汽车在使用和存放过程中,由于物理和化学原因导致的实体价值损耗,例如机械磨损、腐蚀等。无形损耗则是因为科技进步,新车型的出现使得...
4. 无形损耗:汽车的无形损耗指的是因新车型推出导致性能提升、价格下降。 5. 强制保险和税费:购买联合国所属在华机构转让的自用车辆,买家需要支付车辆使用税和车辆购置税。对于农业生产的拖拉机,免征交强险保费...
4. 无形损耗:新车型推出导致性能提升、价格下降。 5. 私人生活用车报废年限:15年。 6. 报废车辆零部件交易:不允许。 7. 所有权验证:确认机动车登记证书、行驶证与卖方身份一致。 8. 右置改左置:不允许交易。 9....
汽车的损耗与维修知识,如有形损耗(物理磨损)和无形损耗(性能下降),对评估车辆剩余价值至关重要。 二手车的鉴定分为静态检查和动态检查。静态检查主要观察车辆外观、内饰、发动机舱等静态状态下的细节,动态...
16. 无形损耗与运输成本:无形损耗通常与技术进步、市场需求变化和品牌效应等因素有关,与运输成本无直接关系。 17. 鉴定评估报告:评估师对其报告的合法性负责,但并不承担交易过程中的所有责任。 18. 现行市价法...
1. **汽车损耗**:汽车损耗分为两种形式,即有形损耗(物理磨损,如机械部件老化、车身划痕等)和无形损耗(技术落后、市场价值下降等)。 2. **使用寿命**:汽车的使用寿命是从投入服务到报废的整个周期,包括正常...
汽车的耗损分为有形损耗(如物理磨损)和无形损耗(如技术落后),维修则包括日常维护和故障修复。汽车的使用寿命包括自然使用寿命(物理磨损导致无法使用)、技术使用寿命(技术过时)和经济使用寿命(维修成本与...
汽车的耗损与维修知识包括有形损耗(如物理磨损)和无形损耗(如品牌价值下降),以及定期保养和故障维修的重要性。汽车的使用寿命涵盖自然使用寿命、技术使用寿命和经济使用寿命,这些都直接影响二手车的评估价值。...
这些操作在每次包含文件时都会执行,无形中增加了程序的开销,尤其是在文件数量较多或文件路径较复杂时,性能损耗会变得更为明显。 其次,作者提到,PHP处理include或require函数时,会先尝试获取文件的opened_path...
4. **汽车的无形损耗是由于(D、性能提升、价格下降的新车型推出)。** - **解析**:正确答案为D。技术进步导致旧款车型价值降低。 5. **根据我国政府有关部门颁布的《汽车报废标准》,9座以下(含9座)的私人生活...
3. 无物理磨损:与硬件不同,软件在运行和使用期间不会因物理损耗导致性能下降。 4. 受限于计算机系统:软件的运行和性能受到硬件、操作系统等多方面的影响。 5. 手工艺式开发:目前,软件开发在很大程度上仍依赖于...
- **无磨损老化**:在正常使用过程中不会出现物理损耗。 - **依赖性**:软件的运行通常依赖特定的硬件环境。 - **手工作坊式开发**:目前仍存在一定的手工编写和调试过程。 - **复杂性**:现代软件系统的规模...
1. 逻辑产品:软件产品是无形的,主要由代码和数据组成。 2. 主要为研制:软件的主要成本在于开发阶段,而非复制。 3. 无物理损耗:软件不会像硬件那样磨损或消耗。 4. 脑力劳动为主:软件开发依赖于智力工作,往往...
19. **车辆购置税**:车辆购置税是购车时必须支付的税费,属于一次性支出,不属于无形损耗。 20. **无负荷测功法**:适用于汽油机和柴油机,可测试发动机性能。 此外,题目还涉及到了机械变速器类型(如CVT)、...
二手车评估师是一个重要的职业,他们负责对二手...此外,还涉及到汽车分类、车辆识别代码、使用寿命判定、车辆税收政策、悬挂系统、发动机工作原理以及汽车电器系统等内容,这些知识是评估二手车价值和性能的重要依据。