降低 COBOL 与其他语言进行交互时产生的性能影响

企业和政府机构常常需要通过 COBOL 与其他语言进行交互来更新其企业系统,这种方式比使用其他语言程序替换 COBOL 程序更有效。实际上,COBOL 接口有一些限制。在本文中,作者会解释让 COBOL 与其他语言进行交互所产生的性能影响,并给出一些提示来避免被动受制于不利影响。

Judith M. Myerson, 系统工程师兼架构师

Judith M. Myerson 是一名系统工程师兼架构师。她感兴趣的领域包括企业级系统、中间件技术、数据库技术、云计算、阈值策略、服务级别协议、行业、网络管理、安全性、 RFID 技术、演示管理和项目管理。她是首批编写和运行资源安全程序并且通过编程实现 COBOL 与 Fortran 和其他语言的交互的 COBOL 程序员。



2012 年 8 月 13 日

简介

几十年前,当我初次开始使用大型机 COBOL 时,我发现它不能与非 COBOL 语言交互。我与一位教授探讨将这作为一个论文题目,主要探讨让 COBOL 与非 COBOL 语言进行交互所产生的性能影响。

为了弄明白可能会有什么性能影响,我基于 “A Fortran Interface to the CODASYL database task group specifications”(参阅 参考资料)试验开发了小型 COBOL/Fortran 接口。Fortran 是当时非常流行的一门语言。

我注意到,一些 COBOL 数据类型在 Fortran 中没有等效的数据类型。不再需要的数据或对象仍然在磁盘上。我看到,当分配的内存超过所需内存时,就会出现堆栈溢出的迹象。我使用正确的 Fortran/COBOL 数据类型解决了这些问题。我在需要时调用子程序,并在不需要时释放它们,以这种方式规避内存限制。当时处理器的容量上限很低,无法与我们今天看到的大容量处理器相比。

在本文中,我会给出一些提示,教您如何避免在 COBOL 与 Java、C/C++、DB2 和 Oracle 进行交互时被动受制于其性能影响。

  1. 避免超时
  2. 使用编译脚本
  3. 遵循数据转换规则
  4. 预防内存泄漏
  5. 删除本地引用

接口性能影响:Java 与 C/C++

在我第一次使用 Fortran 时,它已广泛流行于计算界。如今,Java® 是继 C/C++ 之后最流行的语言,可作为与 COBOL 交互的接口。Fortran 目前深受科学家喜爱,但在普通人群中的流行度则有所下降。

使用 Java 作为接口

您可以让一个 COBOL 程序调用一个 Java 程序,而后者会调用一个不同的 COBOL 程序。如果在设计 Java 程序时不够谨慎,您可能会遇到导致性能影响的内存问题。这些问题包括内存泄漏、高内存使用率、无效对象创建和无效的垃圾收集器行为。其他一些性能问题包括跟踪对象本地引用和在线程中使用本地引用所产生的问题。

Java 中的内存泄漏是由于引用不再需要的对象而产生的。高内存使用的一个来源是低效配置的缓存和并行访问系统的大量活动用户。

当用户负载增加时,无效对象创建会变得很明显,因为垃圾收集器必须不断清理堆积物。这可能导致垃圾收集器具有较高的处理器消耗。当垃圾收集器配置不当时,会发生无效的垃圾收集器行为。

仅当您调用的方法处于运行状态时,对象的本地引用才是有效的。本地引用的自动释放并不总是发生在本地方法返回之后。在显式删除全局引用之前,它们仍然是有效的。当您尝试从一个线程向另一个线程传递本地引用时,本地引用会变得无效。为了确保没有在垃圾收集过程中过早释放对象,Java 虚拟机 (JVM) 会跟踪本地和全局引用。

如果没有显式释放本地引用,系统会在以下两种情况下耗尽内存。

  • 情况 1:您在一个方法中访问一个大型对象,以创建对象的本地引用,将它们用于大量计算。本地引用预防在垃圾收集过程中释放该对象。
  • 情况 2:您没有同时使用一个方法中创建的所有本地引用。在一个 COBOL 方法中,您对一个大型对象数组执行循环,获取元素作为本地引用,并在每一次迭代时对元素进行操作。在每一次迭代之后,不会自动释放对数组元素的本地引用。

使用 C/C++ 作为接口

在一个 C/C++ 程序中,当调用堆栈上使用了过多内存时,就会发生堆栈溢出。堆栈上分配的内存比实际需要的多。回调中的堆栈大小取决于系统架构和可用的内存量。

降低一个给定 C/C++ 程序的有效堆栈大小之后,堆栈溢出情况会更加严重。如果在多线程模式下运行程序,与没有线程支持或分配给单一线程的程序相比,具有多线程的程序每个线程具有更少堆栈空间。

在 COBOL 与 C/C++ 程序之间的调用中,当您尝试调用使用一种语言的函数、而该函数会破坏另一种语言的程序堆栈框架时,就会出现性能问题。对于不会导致有效堆栈框架崩溃和终止的语言,不利影响可能会导致堆栈溢出。

例如,可能无法执行语言的正常清理或退出功能,比如使用 COBOL 在运行单元终止过程中关闭文件,使用非自愿终止的语言清理动态获取的资源。

接口性能影响:IBM DB2 和 Oracle

IBM COBOL for AIX® 与 IBM DB2® 软件一同使用,并且可以与 Oracle 客户端和运行 Tuxedo 的 Oracle 客户端进行集成。执行嵌入式 SQL 语句的 COBOL 程序通过一个名为 SQL Communications Area (SQLCA) 的工作存储区域与 DB2 和 Oracle 进行通信。在运行 SQL 语句之前,系统会检查权限和角色,核对主键并查询外键。它还会检查约束和索引,执行复杂的优化器和事务控制。系统会执行锁定、记录、提交和回滚操作。

不更改默认值或不当配置任何默认值都有可能导致 SQL 执行失败。操作的所有结果都返回到 SQLCA 中的 SQLCODE 和 SQLSTATE 字段中。SQLCODE 提供了有关 SQL 语句是否成功执行的重要信息。

长时间等待锁

超时的一个原因是,对象被另一个用户锁定,或者锁定在另一个会话中,但是应用程序没有检测到该锁定。应用程序等待访问该对象,直至因 DB2 超时而中断。

如果在尝试访问或编辑一个对象时没有更改 LOCK TIMEOUT 的默认值 -1,就不会有锁超时设定。如果在一个 SQL 嵌入语句中使用 SET CURRENT LOCK TIMEOUT 将时间设置为超过 10 秒或 15 秒,就会产生较长的超时延迟。

长时间等待锁会对锁产生不利影响。您会变得不耐烦。如果当前工作单元回滚,您会为此而烦恼。这一失败操作的结果被返回到 SQLCODE 中。

例如,SQLCODE = -901 表示锁超时错误,并且已经为 LOCKTIMEOUT 设定了一个值。SQLCODE = -911 表示有死锁/超时,且执行了回滚。SQLCODE = -913 表示有死锁/超时发生,但没有执行回滚。

SQLCODE 是程序的 WORKING-STORAGE SECTIONLINKAGE SECTION 中的 SQLCA 记录的一部分。更易于将 SQLCODE 添加到 sqlca.cbl。这个样例程序是 checkerr.cbl 的 LINKAGE SECTION 的一部分,checkerr.cbl 是使用 AIX 脚本 (bldapp) 构建的 COBOL 应用程序中的一个 DB2 错误检查实用程序。

高内存需求

在嵌入式 COBOL 语句中,存储过程较动态 SQL 提供了很多优势,其中包括改进的性能和可扩展性。存储过程被优化且以本机语言优化的形式保存。在调用存储过程时,一切准备就绪。当您发送一个 SQL 语句时,查询处理器必须解析它,分析它,然后创建一个要执行的查询计划。

不过,这样做有一个缺点。调用存储过程可能有更高的内存需求。如果这些需求过高,SQL 执行就不会成功。

性能提示

下面是五个提示,可以使用它们避免在 COBOL 与 Java、C/C++、DB2 和 Oracle 进行交互时被动受制于其性能影响。

  • 避免超时
  • 使用编译脚本
  • 预防内存泄漏
  • 删除本地引用

提示 1:避免超时

如果任何 SQLCODE 显示一个超时错误,检查是否将 LOCKTIMEOUT 的默认值更改为较短的时间,比如 10 分钟或 15 秒钟。如果您不确定 LOCKTIMEOUT 的值是什么,请输入以下代码:

db2 "get db cfg  for DBNAME"

然后您会找到包含以下内容的文本:

Lock timeout (sec) (LOCKTIMEOUT) = 30

本例中的值过高,请考虑使用以下命令将其改为 10 秒:

 db2 "update db cfg for DBNAME using LOCKTIMEOUT 10"

假设锁超时没有问题,请寻找以下代码行:

清单 1. 锁超时结果
Locks held currently = 0
Lock waits = 0
Time database waited on locks (ms) =0
Lock list memory in use (Bytes) = 576
Deadlocks detected = 0
Lock escalations = 0
Exclusive lock escalations =  0
Agents currently waiting on locks = 0
Lock timeouts = 0

输出结果显示,正在使用的封锁表内存的大小是 576 字节。如果该大小是您定义的 LOCKLIST 大小的 50%,则需要在 LOCKLIST 数据库配置中增加 4 K 页面的数量。

确定 LOCKTIMEOUT 的值之后,检查是否锁定了当前对象,如果是,请采取适当的措施将其解锁,与将其锁定的用户合作。查看 DB2 主日志,寻找保存 DB2 锁的进程。

如果在 DB2 Connect™ 与您的系统之间有一个防火墙,或者在 DB2 Connect 与 DB2 之间有一个防火墙,您可能需要检查防火墙设置是否造成超时。

提示 2:使用编译脚本

DB2 提供的编译脚本包含一个错误检查实用程序,在编译和链接 COBOL 嵌入式 SQL 和 DB2 应用程序编程接口 (API) 程序时会用到它。您可以在 sqllib/samples/cobol 目录中找到脚本,以及可使用这些文件构建的样例程序。编译文件 bldapp 包含构建 DB2 应用程序的命令,如下所示:

清单 2. 构建应用程序脚本示例
#! /bin/sh
# SCRIPT: bldapp
#
# PART 1: Check if an embedded SQL program exists.
#
# Usage: bldapp <prog_name> [ <db_name> [ <userid> <password> ]]
# Set DB2PATH to where DB2 will be accessed.
# The default is the standard instance path.
DB2PATH=$HOME/sqllib
# If an embedded SQL program, precompile and bind it.
#
if [ -f $1".sqb" ]
then
./embprep $1 $2 $3 $4
fi
#
# PART 2: Compile checkerr.cbl error checking utility.
#
cob2 -qpgmname\(mixed\) -qlib -I$DB2PATH/include/cobol_a \
-c checkerr.cbl
#
# PART 3: Compile the program.
#
cob2 -qpgmname\(mixed\) -qlib -I$DB2PATH/include/cobol_a \
-c $1.cbl
#
# PART 4: Link the program.
#
cob2 -o $1 $1.o checkerr.o -L$DB2PATH/lib -ldb2

在第一部分,第一个参数 $1 指定您的源文件的名称。构建嵌入式 SQL 程序(文件扩展名为 .sqb)需要连接到数据库,因此还提供了三个可选参数:第二个参数 $2 指定您要连接到的数据库的名称;第三个参数 $3 指定数据库的用户 ID,$4 指定密码。

对于一个嵌入式 SQL 程序,bldapp 将参数传递给预编译和绑定脚本 embprep。如果未提供数据库名称,则使用默认的样例数据库。仅当构建程序所在的实例不同于数据库所在的实例时,才需要用户 ID 和密码参数。

第二和第三部分在编译错误检查实用程序和嵌入式 SQL 程序上显示相同的编译器选项。惟一的区别在于 COBOL 程序的名称:checkerr.cbl$1.cbl。参数 $1 被作为您指定的源程序的名称进行传递。

我在下表中解释了每个编译器选项:

表 1. 编译器选项
cob2IBM COBOL Set 编译器的名称。
-qpgmname\(mixed\)使用大小写混合的名称指示编译器准许对库入口点的调用。
-qlib指示编译器处理 COPY 语句。
-c仅执行编译。
-I$DB2PATH/include/cobol_a指定 DB2 include 文件的位置。

第四部分显示用于链接程序的选项。我在下表中解释了每个选项;

表 2. 链接选项
>-o $1指定输出为共享库文件。
$1.o指定存储过程对象文件。
checkerr.o包含实用程序对象文件用于错误检查。
-L$DB2PATH/lib指定 DB2 运行时共享库的位置。如果不指定 -L 选项,那么编译器会默认为以下路径:/usr/lib:/lib.
-ldb2与数据库管理器库链接。

提示 3:预防内存泄漏

为了预防内存泄漏,在对拥有的 Java 对象进行垃圾收集之前,您应当取消通过 Java 加载的任何 COBOL 程序。对 Java 对象的 “finalize” 方法进行以下调用:

runtime.cobcancel("program")

其中 program 是使用 runtime.cobload() 调用加载的 COBOL 程序的名称。以下代码是 Java 程序中 “finalize” 方法的一个示例:

清单 3. “finalize” 方法示例
protected void finalize()
{
    try
    {
        runtime.cobcancel("demoFinalizers");
        System.out.println("demoFinalizers - finalize'ed");
    }
    catch(Exception e)
    {
        System.out.println(
                 "Error during finalize : "+e.getMessage());
    }
}

提示 4: 删除本地引用

您要显式释放不再需要的本地引用。不释放它们会导致系统因缺乏空间供 JVM 跟踪本地(和全局)引用使用而耗尽内存。

使用大型对象进行大量计算需要较高的处理器消耗。在访问一个方法中的对象时会创建本地引用。当您不再需要对象来进行其他计算时,在垃圾收集过程中,本地引用不是自动释放的。您可以使用 Java Native Interface (JNI) 服务 DeleteLocalRef 来显式地释放某个方法中的本地引用。

在一个方法中创建大量本地引用,但不要同时使用所有本地引用。因为 JVM 需要空间来跟踪每个本地引用,您应当释放那些您不需要的引用。

例如,在一个 COBOL 方法中,您对一个大型对象数组执行循环,获取元素作为本地引用,并在每一次迭代时对元素进行操作。您可以在每一次迭代之后释放数组元素的本地引用。

在所有情况下,本地引用仅在创建它们所在的线程中有效。不要将它们从一个线程传递到另一个线程。如果传递它们,当不再需要本地引用时,您将无法释放它们。只要多个线程有可能使用同一引用,您就应当将本地引用转换为全局引用。

结束语

避免在 COBOL 与其他语言进行交互时被动受制于其不利性能影响,这需要提前规划,主动通过性能提示降低或预防不利影响。开发商应当与编程团队就如何预防超时和内存泄漏、删除本地引用进行交流。他们应当更新样例编译文件来简化其工作。

参考资料

学习

  • 阅读 G. M. Stacey 的 A FORTRAN interface to the CODASYL database task group specifications(The Computer Journal, Vol 17, No 8, pp, 124-129, 1972)了解有关的更多信息。
  • 阅读 IBM DB2 通用数据库应用程序开发指南:构建和运行应用程序,了解如何在 AIX 上构建 MicroFocus COBOL 应用程序。
  • 阅读作者撰写的 COBOL 在多线程编程中的局限性 一文,获取有关处理线程的更多信息。
  • 使用 供应链中的 RFID 引领您的组织走向未来,其中解释了业务流程、操作和实现问题、风险、漏洞,以及安全性和隐私。了解 RFID 如何让真实对象与虚拟对象进行交互。
  • 阅读 Judith M. Myerson 撰写的 The Complete Book of Middleware,该文主要关注系统设计的基本原则和优先事项,并强调因电子商务和分布式集成系统的崛起带来的新需求。
  • 通过阅读 企业系统集成,第二版,深入了解企业以及关于如何确保成功的系统集成方面的技术。
  • 浏览 技术书店,阅读关于这些和其他技术主题的图书。
  • developerWorks 技术活动网络广播:随时关注 developerWorks 技术活动和网络广播。
  • AIX and UNIX 专区:developerWorks 的“AIX and UNIX 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 UNIX 技能。
  • AIX and UNIX 新手入门:访问“AIX and UNIX 新手入门”页面可了解更多关于 AIX 和 UNIX 的内容。
  • AIX and UNIX 专题汇总:AIX and UNIX 专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为您把本专区的所有专题进行汇总,让您更方便的找到您需要的内容。
  • AIX and UNIX 下载中心:在这里你可以下载到可以运行在 AIX 或者是 UNIX 系统上的 IBM 服务器软件以及工具,让您可以提前免费试用他们的强大功能。
  • IBM Systems Magazine for AIX 中文版:本杂志的内容更加关注于趋势和企业级架构应用方面的内容,同时对于新兴的技术、产品、应用方式等也有很深入的探讨。IBM Systems Magazine 的内容都是由十分资深的业内人士撰写的,包括 IBM 的合作伙伴、IBM 的主机工程师以及高级管理人员。所以,从这些内容中,您可以了解到更高层次的应用理念,让您在选择和应用 IBM 系统时有一个更好的认识。

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=AIX and UNIX, Java technology, Information Management
ArticleID=830166
ArticleTitle=降低 COBOL 与其他语言进行交互时产生的性能影响
publish-date=08132012