0%

Java 局部变量内存占用的问题

今日面试受挫,记录一下

问题:Java 函数局部变量引用是否需要内存

正文来了:

今天面试了小米,面试官最后问了一道简单的算法题,记录:

用两个队列实现栈,要求实现入栈出栈以及获取大小 三个函数

题目本身并不难,简单实现了一下
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Stack<T> {
private Queue<T> inQueue = new LinkedList<>();
private Queue<T> swapQueue = new LinkedList<>();

public void push(T element) {
if (element == null) {
return;
}
inQueue.add(element);
}

public T pop() {
if (inQueue.isEmpty()) {
return null;
}
while (inQueue.size() > 1) {
swapQueue.add(inQueue.poll());
}
Object target = inQueue.poll();
Queue t = inQueue;
inQueue = swapQueue;
swapQueue = t;
return (T) target;
}

public int getSize() {
return inQueue.size() + swapQueue.size();
}
}

至此,重点来了!!!

来自面试官的灵魂拷问:要求是用两个队列实现,你这不是三个队列吗?
_( 诶 ~ 难道用于交换的局部变量也算么?_(o´・ェ・`o)

来自面试官的灵魂拷问2:你看这个交换的地方,增加了一个变量,内存消耗是不是增加了

说实话,此刻真的有点被问懵了 o((⊙﹏⊙))o.

我寻思好像确实是啊,局部变量也要在虚拟机栈帧中分配内存来着。。。啊嘞 (・∀・*)
不对啊,方法执行肯定有对应的栈帧,众所周知 Java 虚拟机栈帧内需要维护局部变量表、操作数栈 … 等,需要内存记录不是应该的吗,这个也不应该算是内存开销吧

搞得我都有点不自信了,于是一顿操作 javap 大法 javap -v Stack.class 瞅一眼确认一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public T pop();
descriptor: ()Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: getfield #4 // Field inQueue:Ljava/util/Queue;
4: invokeinterface #7, 1 // InterfaceMethod java/util/Queue.isEmpty:()Z
9: ifeq 14
12: aconst_null
13: areturn
14: aload_0
15: getfield #4 // Field inQueue:Ljava/util/Queue;
18: invokeinterface #8, 1 // InterfaceMethod java/util/Queue.size:()I
23: iconst_1
24: if_icmple 49
27: aload_0
28: getfield #5 // Field swapQueue:Ljava/util/Queue;
31: aload_0
32: getfield #4 // Field inQueue:Ljava/util/Queue;
35: invokeinterface #9, 1 // InterfaceMethod java/util/Queue.poll:()Ljava/lang/Object;
40: invokeinterface #6, 2 // InterfaceMethod java/util/Queue.add:(Ljava/lang/Object;)Z
45: pop
46: goto 14
49: aload_0
50: getfield #4 // Field inQueue:Ljava/util/Queue;
53: invokeinterface #9, 1 // InterfaceMethod java/util/Queue.poll:()Ljava/lang/Object;
58: astore_1
59: aload_0
60: getfield #4 // Field inQueue:Ljava/util/Queue;
63: astore_2
64: aload_0
65: aload_0
66: getfield #5 // Field swapQueue:Ljava/util/Queue;
69: putfield #4 // Field inQueue:Ljava/util/Queue;
72: aload_0
73: aload_2
74: putfield #5 // Field swapQueue:Ljava/util/Queue;
77: aload_1
78: areturn
LineNumberTable:
line 18: 0
line 19: 12
line 21: 14
line 22: 27
line 24: 49
line 25: 59
line 26: 64
line 27: 72
line 28: 77
StackMapTable: number_of_entries = 2
frame_type = 14 /* same */
frame_type = 34 /* same */
Signature: #27 // ()TT;

查看 60-69:做了几件事

  • 读取 inQueue 到栈顶
  • 保存到局部变量 2
  • 读取 swapQueue 到栈顶
  • 赋值给 inQueue 变量
  • 把局部变量 2 (原 inQueue)推至栈顶
  • 赋值给 swapQueue

至此,完成两个队列的交换

这么看一下,确实也就是一个局部变量的事儿,也谈不上有啥内存开销啊 ( ╯▽╰)

所以面试官到底是啥意思。。。
以后再研究一下