字节一面两个有意思的题目
投递实习岗位时候字节hr把我捞了起来参加广告部门开发项目组的面试,记录一面问题:
1、malloc、memset和内存实际占用问题
问题描述:
在程序中使用void * p = malloc(2*1024*1024)程序实际内存会占用多少,使用memset(p,4,4)之后内存变化情况如何?
这个问题属实把我问懵了,面试官提示和内存页相关,面试完我自己查了一下觉得应该答案是和page fault相关,我认为的答案是:
1、malloc执行后程序占用没有什么大的变化,因为这样子操作只是在虚拟地址里面映射了一份地址但是实际上还没到真实内存中去使用。(第二种是程序分配的虚拟内存也没有这么多,会导致无效页缺失而出现page fault。) 2、使用memset(p,4,4)的时候需要访问真实的内存区域,需要进行虚拟内存到真实内存的映射,所以会发生内存页缺失问题,也就是当前该进程已有的内存页不足以提供这么大的一块连续内存,此时会产生硬性页缺失page fault),所以内存增长的最大值为当前内存页有的空闲大小,当继续访问额外的区域时候会缺页中断。 3、程序在执行的时候是在虚拟内存中,而不是在真实内存中,对内存的操作都是通过mmu映射到真实内存进行操作,而程序认为自己有很多空间但是实际上目前在实际内存中只有自己有的那部分内存页,当访问超出已有内存页的位置时候会导致缺页中断。
2、操作系统volatile原语
volatile是java面试常用问题,无非是可见性和禁止指令重排,但是还是问出了一点别的东西:
问:volatile有什么特点? 答:可见性和禁止指令重排(有序性) 问:可见性是怎么保证的? 答:可见性是通过禁止使用cache缓存对象实现的,每次使用,线程都会从实际地址中去获取数据,而不会像一般变量有的时候在线程内部维护一个数据,修改也会直接在内存中体现出来,对于多个线程来说,任何一个线程修改了数据都会在别的线程要使用的时候实时展示出来。 问:你了解有序性是基于怎样的原理实现的吗? 答:打扰了。。。 问:你了解内存屏障吗? 答:打扰了 问:ok我了解了 问:这个代码能保证一直执行吗? static int foo; void bar(void) { foo = 0; while (foo != 255) ; } 答:当然可以 问:如果是在多线程环境下能够保证吗,其他线程可能修改foo。 答:应该可以
事实是不可以,因为在执行优化的编译器会导致程序编译后成为下面的代码,不进行实际的代码判断。
void bar_optimized(void) { foo = 0; while (true) ; }
除此之外volatile在不同的语言中也有不同的实现机制,如Java中使用的形式则是在JVM中确定了volatile变量的happens-before原则,从而确保有序和可见,可以说有序性是可见性的保证(我个人看法)。更多详细内容可见volatile和JVM Volatile 读写的happens-before.