拍案叫绝!Jackson内存设计中的组合拳——TextBuffer和BufferRecycler

Jackson作为Java三大Json框架之一,也是SpringBoot的默认序列化框架,具有速度快、内存占用低等特点。在rest服务盛行的今天,序列化和反序列化操作在系统中是一个极其常见的操作,这部分带来的内存开销也是一块重点。今天来看一下Jsckson中为了节省内存的神操作之一——TextBufferBufferRecycler的组合拳。

TextBuffer

TextBuffer是干嘛的?翻译官方注解,可以看作是一个StringBuffer(其实更应该是StringBuilder,因为它也是线程不安全的),但是它有一些骚操作。
StringBuffer在添加内容时,会对char[]进行容量判断,如果不足会进行扩容,并通过数组复制将原数据复制到新数组中。

private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

扩容复制会带来额外的性能开销。
TextBuffer就避免了这种复制,它是怎么做到的?
TextBuffer使用了分段char[]的技术来缓冲内容,其内部持有一个列表private ArrayList<char[]> _segments;用来存放数组,当当前数组不够用了,新申请一个放后面的内容,然后加入到分段列表中。

是不是很简单?!你咋没想到呢?

你以为这就完了吗?还有另一个小伙伴BufferRecycler没登场呢!

BufferRecycler

从名字看出,这应该是一个用来循环利用buffer的一个类?
没错!TextBuffer在需要申请新的空间时,不是自己直接申请内存的,而是向BufferRecycler申请一个新的数组空间。当TextBuffer清空数据时,不会释放空间,而是将空间还给BufferRecycler,来重新利用数组空间。
BufferRecycler自身通过二维数组维护了多个数组的引用,当有其他对象来申请数组空间时,BufferRecycler会将自身持有的数组给对方,如果没有了则新建。当其他对象用完了数组后会将该数组空间的引用还给BufferRecyclerBufferRecycler将该引用记录到自己的二维数组中,以便重新分配。

public char[] allocCharBuffer(int ix, int minSize) {
        final int DEF_SIZE = charBufferLength(ix);
        if (minSize < DEF_SIZE) {
            minSize = DEF_SIZE;
        }
        //从二维数组中拿到buffer引用
        char[] buffer = _charBuffers[ix];
        if (buffer == null || buffer.length < minSize) {
        	//空则进行新分配
            buffer = calloc(minSize);
        } else {
        	//不为空自己不再持有该buffer引用,表示将其分配出去了
            _charBuffers[ix] = null;
        }
        //分配buffer
        return buffer;
    }
public void releaseCharBuffer(int ix, char[] buffer) {
		//将归还过来的buffer的引用记录到自身的二维数组中以便进行复用
        _charBuffers[ix] = buffer;
    }

很简单的设计理念,但简单中透漏着细节和优雅,拍案叫绝!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ImGui(Immediate Mode GUI)是一个用于创建图形用户界面的库,它提供了一系列的UI控件,包括输入框。下面是使用ImGui创建输入框的基本步骤: 1. 导入ImGui库:首先,你需要将ImGui库添加到你的项目。你可以从ImGui的官方网站(https://github.com/ocornut/imgui)下载最新版本的源代码,并将其添加到你的项目。 2. 初始化ImGui:在你的应用程序启动时,需要初始化ImGui。这通常涉及创建一个ImGui上下文,并设置与图形API相关的上下文。 3. 创建输入框:使用ImGui的函数来创建输入框。ImGui提供了`InputText`函数来创建一个文本输入框。你可以指定输入框的标签、默认文本、最大字符数等参数。 4. 处理输入:在每一帧,你需要处理用户的输入并更新输入框的状态。你可以使用ImGui的函数来检查输入框是否被编辑、获取输入框的文本内容等。 5. 渲染UI:最后,你需要在每一帧将UI渲染到屏幕上。这通常涉及调用ImGui的渲染函数,并将UI绘制命令提交给图形API。 下面是一个简单的示例代码,演示了如何使用ImGui创建一个输入框: ```cpp #include <imgui.h> void MyApplication::RenderUI() { ImGui::Begin("Input Box"); static char textBuffer[256] = ""; // 存储输入框的文本内容 ImGui::InputText("Text", textBuffer, sizeof(textBuffer)); if (ImGui::Button("Submit")) { // 处理提交按钮的逻辑 // 可以使用textBuffer的文本内容 } ImGui::End(); } void MyApplication::MainLoop() { while (true) { // 处理输入事件 // 更新UI状态 // 渲染UI RenderUI(); // 刷新屏幕 } } ``` 这只是一个简单的示例,实际使用可能需要更复杂的逻辑来处理输入框的内容和交互。你可以根据自己的需求来扩展和定制UI。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值