如何管理用于高规模服务的单写数据库管理系统?

最近我一直在进行一个项目,旨在创建一个实时高性能的JavaScript图表库。该项目使用了一个雄心勃勃且新颖的技术堆栈,其中包括一个大型的C/C++遗留代码库,使用Emscripten编译为WebAssembly,针对WebGL进行渲染,并提供TypeScript API包装器,可在JavaScript中加载图表而无需担心底层的Wasm。

为什么要使用WebAssembly?

WebAssembly是一项令人兴奋的技术,在许多情况下比JavaScript具有更好的性能优势。而且,在这种情况下,由于遗留的C++代码库已经处理了OpenGL中的大部分图表渲染工作,只需要做一些工作即可将其定位到WebGL。

使用Emscripten将现有的C++代码编译成WebAssembly非常简单,只需编写绑定生成类型并在Wasm库周围编写JavaScript API即可使用它。

在开发库的过程中,我们学到了一些关于WebAssembly内存模型的有趣事实,以及如何避免和调试内存泄漏,下面我将分享给大家。

JavaScript与WebAssembly内存模型的区别

WebAssembly与JavaScript具有完全不同的内存模型。虽然JavaScript拥有自动垃圾回收器,可以自动清理不再需要的变量的内存,但WebAssembly则没有。在Wasm内存中声明的对象或缓冲区必须由调用者删除,否则将导致内存泄漏。

JavaScript中的内存泄漏是如何引起的

无论是JavaScript还是WebAssembly,都可能发生内存泄漏,开发人员必须小心确保在使用WebAssembly时正确清理内存。

尽管JavaScript是一种带有垃圾回收机制的托管式编程语言,但使用纯粹的JavaScript仍然很容易创建内存泄漏。以下是在JavaScript应用程序中无意中导致内存泄漏的几种方式:

  • 箭头函数和闭包可以捕获变量并使其保持活动状态,因此无法被JavaScript垃圾回收器删除。

  • 回调函数或事件监听器可以捕获变量并保持其活动状态。

  • 全局变量或静态变量在应用程序的生命周期中一直存在。如果忘记使用let或const关键字,变量将转换为全局变量。

  • 即使从DOM中分离的节点也可以在JavaScript中保持对象的活动状态。仅仅移除一个节点但保留对它的引用变量,将阻止该节点及其子节点被回收。

WebAssembly中的内存泄漏是如何引起的

Wasm拥有与JavaScript虚拟机不同的堆内存。该内存在浏览器中分配,并从主机操作系统中保留。当您在Wasm中分配内存时,Wasm堆会增长,并且保留了一定范围的地址。当您删除Wasm中的内存时,堆不会缩小,并且内存也不会返回给主机操作系统。相反,内存只是被标记为已删除或可用。这意味着它可以被未来的分配重新使用。

要在WebAssembly中引起内存泄漏,只需分配内存并忘记删除它即可。由于没有自动垃圾回收、终结或将内存标记为不再需要的机制,必须由用户来处理。由编译器Emscripten导出的所有WebAssembly类型都具有一种在使用Wasm内存的对象上调用的`.delete()`函数。当不再需要该对象时,需要调用此函数进行删除。以下是一个快速示例:

示例:Wasm中的内存泄漏

假设您在C++中声明了如下类型:

// person.cpp
#include <string>
class Person {
public:
  // C++ 构造函数
  Person(std::string name, int age) : name(name), age(age) {}
  // C++ 析构函数
  ~Person() {}
  std::string getName() { return name; }
  int getAge() { return age; }
private:
  std::string name;
  int age;
};

`然后使用Emscripten编译和导出该类型,如下所示:

emcc person.cpp -o person.js -s EXPORTED_FUNCTIONS="['_createPerson', '_deletePerson', '_getName', '_getAge']" -s MODULARIZE=1

现在,您可以在JavaScript中实例化、使用和删除该类型,如下所示:

const Module = require('./person.js'); // 包含生成的JavaScript接口
Module.onRuntimeInitialized = () => {
  // 实例化一个Person对象
  const person = new Module.Person('John Doe', 30);
  console.log('创建Person对象:', person);
  // 访问并打印属性
  console.log('姓名:', person.getName());
  console.log('年龄:', person.getAge());
  // 删除Person对象(调用C++析构函数)
  person.delete();
};

然而,如果忘记调用`.delete()`函数,就会导致Wasm内存泄漏。浏览器的内存将增长而不会缩小。

检测WebAssembly应用程序中的内存泄漏

由于内存泄漏对应用程序来说是灾难性的,我们不仅要确保我们的代码不会泄漏内存,还要确保用户代码(即使用我们的JavaScript图表库的应用程序)不会泄漏内存。

为此,我们开发了内部内存调试工具。它实现为一个对象注册表,其中包含所有未删除和未收集的对象的Map<string, TObjectEntryInfo>,其中TObjectEntryInfo是一个存储对象的WeakRef的类型。

通过使用JavaScript代理技术,我们能够拦截对所有WebAssembly类型的new/delete的调用。每次实例化一个对象时,我们将其添加到objectRegistry中;每次删除一个对象时,我们将其从objectRegistry中移除。

现在,您可以运行应用程序,启用内存调试工具,并输出应用程序状态的特定快照。以下是该工具输出的示例。

首先,启用MemoryUsageHelper(内存调试工具):

import { MemoryUsageHelper } from "scichart";
MemoryUsageHelper.isMemoryUsageDebugEnabled = true;

这将自动跟踪我们库中的所有类型,但您也可以通过调用register和unregister来跟踪应用程序中的任意对象:

// 注册一个任意对象
MemoryUsageHelper.register(yourObject, "identifier");
// 注销一个任意对象
MemoryUsageHelper.unregister("identifier");

稍后,在特定的点上通过调用此函数输出一个快照:

MemoryUsageHelper.objectRegistry.log();

这将在控制台输出所有未被删除或未收集的对象和它们的标识符。通过检查这个快照,您可以确定是否有任何内存泄漏。文章来源地址https://www.toymoban.com/diary/apps/652.html

到此这篇关于如何管理用于高规模服务的单写数据库管理系统?的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.toymoban.com/diary/apps/652.html

如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用
无需图数据库的知识图谱和分析,为Gen-AI提供解决方案
上一篇 2024年01月01日 16:56
Python上下文管理器简化-深入理解并简化代码资源的分配与释放
下一篇 2024年01月01日 18:25

相关文章

  • Go如何优雅的写数据库的单测

    ​当你想在代码中测试 Gorm 时,可以考虑使用单元测试或集成测试来确保 Gorm 的功能正常。下面是一个简单的示例,展示了如何编写一个基本的 Gorm 单元测试。 app config config.yaml conf.go services project.go project_test.go init_test.go cmd main.go rootDir, err := os.Getwd() : os.Getwd() 函数用于获取当

    2024年02月03日
    浏览(53)
  • sqlite3 是一个命令行工具,用于与 SQLite 数据库进行交互和管理

    sqlite3 example.db sqlite3 new_database.db sqlite3 -init init_script.sql example.db

    2024年02月09日
    浏览(64)
  • 一台服务器安装两个mysql、重置数据库用于测试使用

    这个方法可以让你不用安装新的数据库,就可以得到一个全新的一个数据库 缺点:原来的数据库被暂停使用 优点:数据切换速度快 更改mysql配置文件 重启mysql 使用data02为新的存储数据的地方 配置文件的datadir参数也更改成这个文件夹 对数据库进行初始化 查看初始化密码 重

    2024年02月19日
    浏览(97)
  • Flink与Cassandra:如何在大规模数据处理中存储与管理数据

    作者:禅与计算机程序设计艺术 1.1. 背景介绍 随着大数据时代的到来,数据处理的需求也越来越大。在实际工作中,我们常常需要处理海量数据,如何高效地存储与管理数据成为了我们必须面对的问题。 1.2. 文章目的 本文旨在探讨如何在大型数据处理环境中使用 Flink 和 Ca

    2024年02月13日
    浏览(57)
  • 区块链:OpenDataPlatform如何与区块链结合用于数据存储和管理

    作者:禅与计算机程序设计艺术 区块链(Blockchain)近年来受到越来越多人的关注,因为其能够提供不可篡改、透明、安全、高效率的数据存证功能。随着其功能的不断完善,越来越多的创业公司都开始使用区块链技术进行数据存证及管理。然而,不同于传统互联网应用中的数据

    2024年02月12日
    浏览(56)
  • 什么是T-SQL编程?T-SQL是Transact-SQL的缩写,是一种扩展了SQL(结构化查询语言)的编程语言,用于Microsoft SQL Server数据库管理系统中的数据管理和操作。T-

    什么是T-SQL编程? T-SQL是Transact-SQL的缩写,是一种 扩展了SQL(结构化查询语言) 的编程语言,用于Microsoft SQL Server数据库管理系统中的数据管理和操作。T-SQL支持创建 存储过程、触发器、函数 等高级特性,能够更加灵活地进行数据操作和处理。基本的T-SQL语法与标准SQL很相

    2024年01月21日
    浏览(97)
  • 【数据库大作业--酒店服务管理系统】

    在学习《数据库系统原理教程》等相关课程时,期末的结课作业往往是设计一个数据库系统。设计开发过程中,大多数只是注重需求分析、概念结构设计、逻辑结构设计、数据库实施、运行测试等主要环节。本篇博客即为本人的结课作业,本人才疏学浅,文章中如有错误之处

    2024年02月07日
    浏览(62)
  • 【postgresql 基础入门】数据库服务的管理

    ​ 专栏内容 : postgresql内核源码分析 手写数据库toadb 并发编程 ​ 开源贡献 : toadb开源库 个人主页 :我的主页 管理社区 :开源数据库 座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物. 初始化集群 数据库服务管理 postgresql 数据库是一款通用的关系型数据,在开

    2024年02月10日
    浏览(54)
  • 服务器管理平台开发(2)- 设计数据库表

    本篇文章主要对数据管理平台数据库表设计进行介绍,包括单库多表设计、SQL语句、视图构造等 设备品牌、序列号、型号等使用业务主表进行记录,逻辑磁盘、PCI设备可能出现1对N的情况,分别使用PCI设备表、Mac地址表、逻辑磁盘表、应用程序表、登录日志表进行记录 构建虚

    2024年01月22日
    浏览(64)
  • 如何远程管理天翼云RDS数据库

            天翼云MySQL RDS数据库当前仅允许从云主机内网访问,暂时不支持绑定公网IP地址远程访问和控制数据库。很多用户更习惯使用Windows上的图形客户端对数据库进行管理,如果有Windows云主机则可以远程桌面登录到Windows云主机上使用MySQL-Front或Navicat等图形客户端访问

    2023年04月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包