Java 临时内存中的卡片对象实例

Java Card Object Instance in Transient Memory

我正在开发 Java Card 小程序(用于 Java Card 2.2.1),它需要一些临时对象来处理 APDU 命令。我对正确的内存管理有疑问。 我花了很多时间研究这些问题,但我没有在某些 java 卡片 API 上找到任何说明或好的示例代码。我有两个主要问题:

  1. 如何创建临时对象数组(我指的是 RAM 中的自定义对象,而不是 EEPROM 中的自定义对象)。我读过 makeTransientObjectArray 但它 returns 只是对象类型的数组。我知道如何使用 makeTransientByteArray 创建瞬态字节数组,但我的问题是关于对象实例的瞬态数组。或者可以用 java 语言以任何方式将字节数组转换为实例而不进行序列化?

  2. 我只在传入 APDU 命令的过程中需要这个临时对象数组,不需要保留为我分配的内存。分配此临时内存的最佳位置在哪里(在 installselectprocess、... 函数内)?

Edited for more explanations:

  1. 正如我已经从文档中读到的,任何对象实例都存储在 EEPROM 中。假设我知道我的过程算法中需要的最大对象数(比如 100)。我在 install 方法中生成了 100 个 MyClass 实例。 MyClass 的每个实例包含 3 个字段:field1 是一个短类型,field2 是一个字节,field3 是一个短类型。所有这 100 个实例将通过 APDU 命令的输入来填充。如果对于每个命令,我都在 EEPROM 上填充对象,这不是一个好的做法,因为它们是临时数据。 EEPROM 也有最大写入次数。一种方法可能是,对于每个实例,我使用 makeTransientByteArraymakeTransientShortArray 为每个对象分配 5 个字节。但是正如我从文档中读到的那样,它按集群分配内存(32 字节 - 不确定大小),这是无效的。那么在这种情况下我必须做什么?

  2. 我的意思是瞬时记忆怎么办。如果在安装函数中分配临时内存,其他小程序将无法使用。如果小程序是卡上唯一的一个小程序,最好在 install 函数中分配所有临时内存。我想知道适用于所有条件(单个小程序设备或多小程序设备)的通用有效方法。我也不确定,如果在 install 内分配的瞬时内存,只要将卡插入卡 reader.

  3. 中,进程函数内是否可用

How can I create an array of transient objects (I mean custom objects in RAM not in EEPROM).

JavaCard 规范提供了一种方法makeTransientObjectArray(short, byte) 来创建瞬态对象数组。这将在 RAM 上分配内存,然后您可以将对象的引用存储在该内存中。

Object[] aob = JCSystem.makeTransientObjectArray(lengthOfArray, CLEAR_ON_..event);
aob[0] = ((YourClass)new YourClass(param));
aob[1] = ((YourClass)new YourClass(param));
..

但是,您仍然无法完全实现您的目标,因为在 YourClass 中实例化的对象可能仍在消耗来自 非瞬态内存 (EEPROM) 的内存transient (RAM) 取决于它们在 YourClass 的构造函数中的分配。它只是 YourClass 对象的引用是您存储在瞬态 space (aob) 中的内容。

I need this transient array of objects only during process of incoming APDU command and not need to keep the memory allocated for me. Where is the best place to allocate this transient memory (inside install, select, process, ... functions)?

所有资源最好用install()方法分配。

不幸的是,在 Java 卡的经典规范中,您尝试做的事情是不可能的。对象实例总是存储在 EEPROM 中,正如您自己已经注意到的那样。所以你必须解决这个问题。

Java 是一种相对高级的语言,其中对象总是存储在一块特定的内存中。现在他们已经将这种类型的内存更改为 Java 卡的持久内存。然而,这将需要对语言进行彻底的重新设计,以允许在一种或另一种类型的内存中构造对象。如今,JCF 当然可以考虑为此使用注释——这仍然非常棘手,但可能可行。

同样,不可能只通过一种处理方法使对象存在,即使是数组类型也是如此。要实现这一点,您必须拥有附加堆或实时垃圾收集器。管理一个堆和堆栈向彼此增长已经够难了,实时 GC 也不是当前经典实现中存在的东西。我们在这里的环境非常受限。

所以基本上你必须绕过平台的限制。


一个好的策略是创建包含瞬时内存或引用现有内存的对象缓存 ,例如 APDU 缓冲区中的内存 。这些对象将在安装或个性化期间创建。然后可以在必要时检索、使用这些对象并将其返回到缓存。为了给您一个想法,请查看 Java 的 ByteBuffer.wrap() 方法,该方法允许您对现有数组的一部分执行缓冲区操作。现在考虑该类型的可重用对象。

另一个合乎逻辑的解决方案是根本不使用 OO 编程。嘿,OO 很好很花花公子,但我们在这里谈论的是内存为 8 到 10 KiB 的芯片 最大。会有限制。可以用对象完成的事情通常也可以只用方法来完成(实际上,你可以证明是这种情况,因为没有对象的 Java 无疑是图灵完备的,但如果你被卡住了,这就没有什么安慰了与您的设计)。


关于您的文字的注释:

  • 不,您不能将字节数组转换为对象实例。一般而言,这将适用 Java 和 OO 的所有原则。如果可能的话,包括数据封装在内的一切都会被破坏。您当然可以反序列化自己并将结果放入缓存之外的对象中(参见上面的策略)。
  • 通常只应在安装或个性化期间分配内存,或者很可能在发布后使​​用延迟实例化分配一次。
  • 您不需要 100 个活动对象。在某个特定时间,您只有几个对象需要 "alive"。利用这些信息!
  • 内存分配特定于平台实现。肯定有 "cluster" 尺寸更小的平台;平台一般会尝试对齐内存中的数据,所以这也取决于系统/芯片的设计。
  • 使用 CLEAR_ON_DESELECT 创建的内存可能可供其他小程序使用。如果他们被选中,那么这个 RAM 就不再需要了。一个聪明的实现会将内存保持在堆的顶部(仍然很棘手,但是嘿)。正如所指出的,这在选择实例后变得可用。 process 方法只会在 之后 小程序被选中(即使是处理最初的 SELECT APDU 本身)。