Java for 循环中的卡内存泄漏?
Java Card memory leak in for loop?
我知道 Java Card VM 没有垃圾收集器,但是 for
循环会发生什么:
for(short x=0;x<10;x++)
{}
x
变量是在 for
循环后得到利用,还是变成垃圾?
以防万一我有一个大小为 2 的名为 index
的瞬态字节数组(而不是 for
循环中的 i
)并且我在 [=13= 中使用该数组]循环:
for(index[0]=0;index[0]<10;index[0]++)
{}
但是比第一个版本慢了一点。如果我在 for
循环中为索引使用普通变量,那么它会变得非常慢。
那么,第一个 for
循环中的 x
变量发生了什么?这样使用 for
循环是否安全?
让我们简单介绍一下内存。简而言之,智能卡中有以下3种类型的记忆:
- ROM(有时是 FLASH)
- EEPROM
- 内存
ROM:
卡的 OS 和 Java 卡 API 和一些工厂专有包存储在这里。这个内存的内容是固定的,你不能修改它。在芯片生产中写入此内存仅发生一次,该过程被命名为 Masking.
EEPROM:
这是您的小程序加载到的可修改内存,它由 4 个部分组成,名称如下:
- 文本:也称为代码段,包含程序的机器指令。代码可以被认为是小说的文本:它讲述了程序做什么的故事
- Data : 包含程序的静态数据,即在整个程序执行过程中存在的变量。 C 或 C++ 程序中的全局变量是静态的,在 C、C++ 或 Java.
中声明为静态的变量也是如此
- Heap : 是一个内存池,用于动态分配内存,例如 C 中的
malloc()
或 C++ 中的 new
和 Java.
- 堆栈:包含系统堆栈,用作临时存储。
断电(比如撕卡)对这段内存的内容没有任何影响。
内存:
这也是一种可修改的内存类型。 RAM 和 EEPROM 之间的三个主要区别:
- RAM 确实比 EEPROM 快。 (快 1000 倍)
- RAM 的内容会在断电时被破坏。
- EEPROM的写入次数有限(一般为100.000次),而RAM的写入次数要多一些。
然后呢?
当你写for(short x=0; x<10; x++)
时,你将x
定义为局部变量。局部变量存储在 Stack 中。堆栈指针将在掉电时重置,并且已使用的堆栈部分将被回收。所以Garbage Collector缺失的主要问题是关于Heap.
即,当您使用 new
关键字定义局部变量时,您将堆的那部分永远指定为局部变量。当运行时环境完成该方法时,该对象将销毁并变得不可用,而堆的那部分不会被回收。所以你会失去那部分Heap。您用于 for
循环的案例似乎没问题,并且不会造成任何问题,因为您没有使用 new
关键字。
请注意,在较新版本的 Java Card(2.2.2 及更高版本)中,有一个手动垃圾收集器(查看 JCSystem.requestObjectDeletion documentation). But consider that it is really slow and even dangerous in some situations(Look 问题)。
x
变量在字节码中并不真正存在。 Java 堆栈中的某个位置表示 x
(无论是 Java 字节码还是 Java 卡转换器转换后的代码)。现在 Java 堆栈是一个虚拟堆栈。该堆栈是在具有寄存器和非虚拟堆栈的 CPU 上实现的。通常,如果有足够的寄存器可用,那么变量 x
会简单地放入一个寄存器中,直到它超出范围。寄存器当然可以重复使用。 CPU 堆栈本身是瞬态存储器 (RAM) 中的 LIFO(后进先出)队列。在执行构成您的 Applet 的字节码期间,堆栈会不断增长和收缩。像寄存器一样,堆栈内存被一遍又一遍地重复使用。所有局部变量(在代码块和方法参数中定义的变量)都以这种方式处理。
如果将变量放在瞬态数组中,那么就是将变量放在基于 RAM 的堆上。 Java 卡 RAM 堆永远不会超出范围。这意味着如果您更新需要将更改写入临时内存的值。正如您通过实验发现的那样,这当然比 CPU 寄存器的本地化更新慢。通常瞬态内存中的内存永远不会被释放。也就是说,您当然可以将内存重用于其他目的,只要您拥有对数组的引用即可。请注意,引用本身(index[0]
中的 index
)可能在持久内存(EEPROM 或闪存)或临时内存中。
不清楚 "normal variable" 是什么意思。如果这是用 new
创建的东西,或者如果它是对象实例中的 字段 ,那么它会保留在持久内存(EEPROM 或闪存)的堆中。 EEPROM 和闪存的写入周期 数量有限,写入EEPROM 或闪存比写入RAM 慢多。
Java 卡片包含两种暂存:CLEAR_ON_RESET和CLEAR_ON_DESELECT。两者的区别在于CLEAR_ON_RESET允许内存在Applet实例之间共享,而CLEAR_ON_DESELECT允许内存被不同的Applet重用。
Java Card classic 不包含在 Applet 执行期间运行的垃圾收集器,您通常只能在启动期间使用 JCSystem.requestObjectDeletion()
请求垃圾收集,这将清理未引用的内存不再,无论是在瞬时内存中的堆上还是在持久内存中。清理内存就是扫描所有内存,标记所有未被引用的块,然后压缩内存。这类似于对硬盘进行碎片整理;这可能需要很长时间。
ROM 在制造阶段被填充。它可能包含操作系统、Java Card API 实现、预加载小程序的字节码(包括常量)等。它只能在现场读取,因此没有任何影响对于所问的问题。
我知道 Java Card VM 没有垃圾收集器,但是 for
循环会发生什么:
for(short x=0;x<10;x++)
{}
x
变量是在 for
循环后得到利用,还是变成垃圾?
以防万一我有一个大小为 2 的名为 index
的瞬态字节数组(而不是 for
循环中的 i
)并且我在 [=13= 中使用该数组]循环:
for(index[0]=0;index[0]<10;index[0]++)
{}
但是比第一个版本慢了一点。如果我在 for
循环中为索引使用普通变量,那么它会变得非常慢。
那么,第一个 for
循环中的 x
变量发生了什么?这样使用 for
循环是否安全?
让我们简单介绍一下内存。简而言之,智能卡中有以下3种类型的记忆:
- ROM(有时是 FLASH)
- EEPROM
- 内存
ROM:
卡的 OS 和 Java 卡 API 和一些工厂专有包存储在这里。这个内存的内容是固定的,你不能修改它。在芯片生产中写入此内存仅发生一次,该过程被命名为 Masking.
EEPROM:
这是您的小程序加载到的可修改内存,它由 4 个部分组成,名称如下:
- 文本:也称为代码段,包含程序的机器指令。代码可以被认为是小说的文本:它讲述了程序做什么的故事
- Data : 包含程序的静态数据,即在整个程序执行过程中存在的变量。 C 或 C++ 程序中的全局变量是静态的,在 C、C++ 或 Java. 中声明为静态的变量也是如此
- Heap : 是一个内存池,用于动态分配内存,例如 C 中的
malloc()
或 C++ 中的new
和 Java. - 堆栈:包含系统堆栈,用作临时存储。
断电(比如撕卡)对这段内存的内容没有任何影响。
内存:
这也是一种可修改的内存类型。 RAM 和 EEPROM 之间的三个主要区别:
- RAM 确实比 EEPROM 快。 (快 1000 倍)
- RAM 的内容会在断电时被破坏。
- EEPROM的写入次数有限(一般为100.000次),而RAM的写入次数要多一些。
然后呢?
当你写for(short x=0; x<10; x++)
时,你将x
定义为局部变量。局部变量存储在 Stack 中。堆栈指针将在掉电时重置,并且已使用的堆栈部分将被回收。所以Garbage Collector缺失的主要问题是关于Heap.
即,当您使用 new
关键字定义局部变量时,您将堆的那部分永远指定为局部变量。当运行时环境完成该方法时,该对象将销毁并变得不可用,而堆的那部分不会被回收。所以你会失去那部分Heap。您用于 for
循环的案例似乎没问题,并且不会造成任何问题,因为您没有使用 new
关键字。
请注意,在较新版本的 Java Card(2.2.2 及更高版本)中,有一个手动垃圾收集器(查看 JCSystem.requestObjectDeletion documentation). But consider that it is really slow and even dangerous in some situations(Look
x
变量在字节码中并不真正存在。 Java 堆栈中的某个位置表示 x
(无论是 Java 字节码还是 Java 卡转换器转换后的代码)。现在 Java 堆栈是一个虚拟堆栈。该堆栈是在具有寄存器和非虚拟堆栈的 CPU 上实现的。通常,如果有足够的寄存器可用,那么变量 x
会简单地放入一个寄存器中,直到它超出范围。寄存器当然可以重复使用。 CPU 堆栈本身是瞬态存储器 (RAM) 中的 LIFO(后进先出)队列。在执行构成您的 Applet 的字节码期间,堆栈会不断增长和收缩。像寄存器一样,堆栈内存被一遍又一遍地重复使用。所有局部变量(在代码块和方法参数中定义的变量)都以这种方式处理。
如果将变量放在瞬态数组中,那么就是将变量放在基于 RAM 的堆上。 Java 卡 RAM 堆永远不会超出范围。这意味着如果您更新需要将更改写入临时内存的值。正如您通过实验发现的那样,这当然比 CPU 寄存器的本地化更新慢。通常瞬态内存中的内存永远不会被释放。也就是说,您当然可以将内存重用于其他目的,只要您拥有对数组的引用即可。请注意,引用本身(index[0]
中的 index
)可能在持久内存(EEPROM 或闪存)或临时内存中。
不清楚 "normal variable" 是什么意思。如果这是用 new
创建的东西,或者如果它是对象实例中的 字段 ,那么它会保留在持久内存(EEPROM 或闪存)的堆中。 EEPROM 和闪存的写入周期 数量有限,写入EEPROM 或闪存比写入RAM 慢多。
Java 卡片包含两种暂存:CLEAR_ON_RESET和CLEAR_ON_DESELECT。两者的区别在于CLEAR_ON_RESET允许内存在Applet实例之间共享,而CLEAR_ON_DESELECT允许内存被不同的Applet重用。
Java Card classic 不包含在 Applet 执行期间运行的垃圾收集器,您通常只能在启动期间使用 JCSystem.requestObjectDeletion()
请求垃圾收集,这将清理未引用的内存不再,无论是在瞬时内存中的堆上还是在持久内存中。清理内存就是扫描所有内存,标记所有未被引用的块,然后压缩内存。这类似于对硬盘进行碎片整理;这可能需要很长时间。
ROM 在制造阶段被填充。它可能包含操作系统、Java Card API 实现、预加载小程序的字节码(包括常量)等。它只能在现场读取,因此没有任何影响对于所问的问题。