SmallObjectAllocator实作

深入Android系统(二)Bionic库 Bionic库是Android的基础库之一,也是连接Android和Linux的桥梁。Bionic库中包含了很多基本系统功能接口,这些功能大部分来自 Linux,但是和标准的 Linux 之间有很多细微差别。同时Bionic库中增加了一些新的模块(像log、linker),服务于Android的上层代码。 导读 为甚有导读呢,因为Bionic库这部分学起来太枯燥了,在实际开发过程中几乎没主动使用过,不过并不代表它不存在哈,这哥们无处不在。。。 通过Bionic库的学习呢,至少可以: 了解Andro. 阅读详情

#ifndef _ALLOC_H_
#define _ALLOC_H_
#pragma once

#include <new>
#include "Assert.h"

#ifndef NULL
#define NULL 0
#endif

namespace KOK
{
    class __CSimpleAlloc
    {
    public:
        static void* Allocate(size_t n)
        {
            if(n != 0) return ::operator new(n);
        }

        static void Deallocate(void* p)
        {
            if(p != NULL) return ::operator delete(p);
        }

        static void Deallocate(void* p, size_t n)
        {
            if(p != NULL) return ::operator delete(p);
        }
    };

    class __CSmallObjectAlloc
    {
    private:
        struct CChunk
        {
            unsigned char* pData;//the real chunk address
            unsigned char availableBlockIndex; //first available block index
            unsigned char availableBlockCount; //the maximun block count is 255
            CChunk* pNext;

            CChunk(unsigned char blockCount, size_t blockSize)
            {
                availableBlockCount = blockCount;
                availableBlockIndex = 0;
                pNext = NULL;
                unsigned char* pDataTemp = pData = (unsigned char*)malloc(blockCount * blockSize);
                unsigned char i = 0;
                while(i ^ blockCount) //initial next available index, act as a signal list
                {
                    *pDataTemp = (++i);
                    pDataTemp += blockSize;
                }
            }

            ~CChunk()
            {
                free(pData);
            }

            inline bool IsAvailable()
            {
                return availableBlockCount != 0;
            }

            //locate the block specified by pointer p
            inline unsigned char GetBlockIndex(unsigned char* p, unsigned blockSize)
            {
                KOK_ASSERT((p != NULL) && (p >= pData) && ((p - pData) % blockSize == 0));

                return (p - pData)/blockSize;

            }

            //alloc, make blocks link each other like a signal list
            unsigned char* GetBlock(unsigned blockSize)
            {
                KOK_ASSERT(availableBlockCount != 0);
                availableBlockCount--;
                unsigned char pTemp = availableBlockIndex;
                if(availableBlockCount)
                {
                    availableBlockIndex = *(pData + blockSize * availableBlockIndex);
                }

                return pData + blockSize * pTemp;
            }

            //dealloc, add free block to the front of slist
            void PutBlock(unsigned char* p, unsigned blockSize)
            {
                KOK_ASSERT((p != NULL) && (p >= pData) && ((p - pData) % blockSize == 0) );
                availableBlockCount++;
                *p = availableBlockIndex;
                availableBlockIndex = GetBlockIndex(p, blockSize);

            }

        };

        struct CFixAlloc
        {
            unsigned char blockCount; //block count, 255 is max.
            size_t blockSize; //block size, in gerneral it doesnt exceed 128k
            unsigned availableChunkCount; //available chunk count, which is uesed to justify if fix allocator leaves one available chunk at least.
            CChunk* pFirst;//chunk list
            CChunk* pCurFreePrev;
            CChunk* pCurFree;//free cache
            CChunk* pCurAlloc;//alloc cache
            CFixAlloc* pNext;

        private:
            inline CChunk* NewChunk()
            {
                return new CChunk(blockCount, blockSize);
            }

            //locate the chunk specified by pointer p
            inline bool IsInChunk(unsigned char* p, CChunk* pChunk)
            {
                KOK_ASSERT(p != NULL);
                return p >= pChunk->pData && p <= pChunk->pData + blockCount * blockSize;
            }

            void PutBlockAux(unsigned char* p, CChunk*& pChunk, CChunk*& pChunkPrev)
            {
                pChunk->PutBlock(p, blockSize);

                if(pChunk->availableBlockCount == 1) //in the condition of put a block from full used chunk, note while blockCount == 1
                    availableChunkCount++;

                if(pChunk->availableBlockCount == blockCount) //all the blocks are free
                {
                    if(availableChunkCount > 1) //leave one available chunk at least(exclude itself)
                    {
                        if(pChunk == pChunkPrev) //in the condition of first chunk would be freed
                            pFirst = pChunk->pNext;
                        else
                            pChunkPrev->pNext = pChunk->pNext; //remove all-blocks free chunk from slist
                        free(pChunk); //free the chunk
                        if(pChunk == pCurAlloc) //update cache accordingly
                            pCurAlloc = NULL;
                        pChunk = NULL;
                        availableChunkCount--;
                    }
                }

            }

        public:
            CFixAlloc(unsigned blockSize, unsigned char blockCount = 255)
            {
                this->blockSize = blockSize;
                this->blockCount = blockCount;
                availableChunkCount = 0;
                this->pNext = NULL;
                this->pFirst = this->pCurAlloc = this->pCurFree = this->pCurFreePrev = NULL;
            }

            ~CFixAlloc()
            {
                CChunk* pTemp = NULL;
                while(pFirst != NULL)
                {
                    pTemp = pFirst;
                    pFirst = pFirst->pNext;
                    delete pTemp;
                }
            }
            void PutBlock(unsigned char* p)
            {
                KOK_ASSERT(p != NULL);
                if(pCurFree != NULL &&  IsInChunk(p, pCurFree)) //case 1: cache hits
                {
                    PutBlockAux(p, pCurFree, pCurFreePrev);
                }
                else //case 2: search the approciate chunk from head of link
                {
                    CChunk* pTargetChunk = pFirst;
                    CChunk* pTargetChunkPrev = pFirst;
                    while(pTargetChunk != NULL)
                    {
                        if(IsInChunk(p, pTargetChunk))
                        {
                            PutBlockAux(p, pTargetChunk, pTargetChunkPrev);
                            break;
                        }
                        else
                        {
                            pTargetChunkPrev = pTargetChunk;
                            pTargetChunk= pTargetChunk->pNext;
                        }
                    }
                    pCurFree = pTargetChunk; //update free cache
                    pCurFreePrev = pTargetChunkPrev;
                }
            }

            //alloc
            unsigned char* GetBlock()
            {
                unsigned char* pReturn;
                CChunk* pAvailableChunk = pFirst;
                if(pCurAlloc != NULL && pCurAlloc->IsAvailable()) //case 1: cache hits
                {
                    pReturn = pCurAlloc->GetBlock(blockSize);
                    if(!pCurAlloc->IsAvailable())
                        availableChunkCount--;
                }
                else //case 2: find the first available chunk from head of link
                {
                    while(pAvailableChunk != NULL)
                    {
                        if(pAvailableChunk->IsAvailable())
                        {
                            pReturn = pAvailableChunk->GetBlock(blockSize);

                            if(!pAvailableChunk->IsAvailable())
                                availableChunkCount--;
                            break;
                        }
                        else
                        {
                            pAvailableChunk = pAvailableChunk->pNext;
                        }
                    }
                    if(pAvailableChunk == NULL) //case 3: if all the chunks are used, alloc a new chunk
                    {
                        pAvailableChunk = NewChunk();
                        pAvailableChunk->pNext = pFirst; //add a new chunk to the front of slist
                        pFirst = pAvailableChunk;
                        pReturn = pAvailableChunk->GetBlock(blockSize);
                        if(pAvailableChunk->IsAvailable())// in condition of blockcount == 1
                            availableChunkCount++;
                    }
                    pCurAlloc = pAvailableChunk;//update cache
                }
                return pReturn;
            }

        };

    private:
        CFixAlloc* m_pFirst_; //fix allocator link
        CFixAlloc* m_pCurAlloc_; //cache
        CFixAlloc* m_pCurFree_; //cache
        size_t m_nAlign_;
        size_t m_blockCount_; //number of blocks per chunk

    protected:
        inline bool IsInFixAlloc(size_t n, CFixAlloc* pAlloc)
        {
            return n == pAlloc->blockSize;
        }

    public:
        __CSmallObjectAlloc(size_t nAlign = sizeof(char*), size_t nBlockCount = 255)
        {
            m_pFirst_ = m_pCurAlloc_ = m_pCurFree_ = NULL;
            m_nAlign_ = nAlign;
            m_blockCount_ = nBlockCount;
        }

        ~__CSmallObjectAlloc()
        {
            CFixAlloc* pTemp = NULL;
            while(m_pFirst_ != NULL)
            {
                pTemp = m_pFirst_;
                m_pFirst_ = m_pFirst_->pNext;
                delete pTemp;
            }
        }

        void* Allocate(size_t n)
        {
            n = (n + m_nAlign_ - 1) & ~(m_nAlign_ - 1); // align

            if(n > 128) //big object allocator
                return ::operator new(n);
            else //small object allocator
            {
                if(m_pCurAlloc_ != NULL && IsInFixAlloc(n, m_pCurAlloc_))
                {
                    return m_pCurAlloc_->GetBlock();
                }
                else
                {
                    CFixAlloc* pTargetFixAlloc = m_pFirst_;
                    while(pTargetFixAlloc != NULL)
                    {
                        if(IsInFixAlloc(n, pTargetFixAlloc))
                        {
                            m_pCurAlloc_ = pTargetFixAlloc;//update cache
                            return pTargetFixAlloc->GetBlock();
                        }
                        else
                            pTargetFixAlloc = pTargetFixAlloc->pNext;
                    }
                    if(pTargetFixAlloc == NULL)
                    {
                        pTargetFixAlloc = new CFixAlloc(n,m_blockCount_);
                        pTargetFixAlloc->pNext = m_pFirst_;
                        m_pFirst_ = m_pCurAlloc_ = pTargetFixAlloc; //update cache
                        return pTargetFixAlloc->GetBlock();
                    }
                }
            }
        }
        void Deallocate(void* p, size_t n)
        {
            KOK_ASSERT(p != NULL);
            n = (n + m_nAlign_ - 1) & ~(m_nAlign_ - 1);//align

            if(n > 128)
            {
                ::operator delete(p);
                return;
            }

            if(m_pCurFree_ != NULL && IsInFixAlloc(n, m_pCurFree_))
            {
                m_pCurFree_->PutBlock((unsigned char*)p);
            }
            else
            {
                CFixAlloc* pTargetFixAlloc = m_pFirst_;
                while(pTargetFixAlloc != NULL)
                {
                    if(IsInFixAlloc(n, pTargetFixAlloc))
                    {
                        m_pCurFree_ = pTargetFixAlloc; //update cache
                        pTargetFixAlloc->PutBlock((unsigned char*)p);
                        break;
                    }
                    else
                        pTargetFixAlloc = pTargetFixAlloc->pNext;
                }

                KOK_ASSERT(pTargetFixAlloc != NULL);
            }
            return;
        }
    };

    class CSmallObjectAlloc
    {
    private:
        CSmallObjectAlloc();
        CSmallObjectAlloc(const CSmallObjectAlloc&);
        CSmallObjectAlloc& operator=(const CSmallObjectAlloc&);

    private:
        static __CSmallObjectAlloc objectAllocator;

    public:
        static void* Allocate(size_t n)
        {
            return objectAllocator.Allocate(n);
        }

        static void Deallocate(void* p, size_t n)
        {
            objectAllocator.Deallocate(p, n);
        }

    };

    __CSmallObjectAlloc CSmallObjectAlloc::objectAllocator;

    template <class T, class Value>
    inline void Construct(T* p, Value& value)
    {
        new(p) T(value);
    }

    template <class T, class Value>
    inline void Construct(T* p)
    {
        new(p) T();
    }

    template <class T>
    inline void Destroy(T* p)
    {
        p->~T();
    }

    #define _USE_CUSTOM_ALLOC_
    #ifndef _USE_CUSTOM_ALLOC_
    typedef __CSimpleAlloc alloc;
    #else
    typedef CSmallObjectAlloc alloc;
    #endif

    template <class T, class Alloc = alloc>
    class CAllocAdapter
    {
    public:
        static T* Allocate(size_t n)
        {
            return n == 0 ? 0 : (T*)Alloc::Allocate(n * sizeof(T));
        }

        static T* Allocate(void)
        {
            return (T*)Alloc::Allocate(sizeof(T));
        }

        static void Deallocate(T* p)
        {
            Alloc::Deallocate(p, sizeof(T));
        }

        static void Deallocate(T* p, size_t n)
        {
            Alloc::Deallocate(p, n);
        }

    };
}
#endif

小目标检测中的数据扩展(Augmentation for small object detection) Abstract 这些年来目标检测领域经历了令人印象深刻的进展。除了这些改进,在小目标检测与大目标检测领域还是有不小的差距。我们在MS COCO上分析了当前SOTA的模型Mask-RCNN。研究成果展示GT目标与预测的anchors的重叠远远小于期望的IoU阈值。我们猜测这可能是由两个情况导致的:1、只有少部分样本包含小目标;2、及时在包含小目标的样本中,小目标的数目也不够。我们因此提出过... 阅读详情

相关推荐

GD32F103入门实践(一)配置环境,搭建工程模板,烧写程序

写在前面 本系列博客是我初学GD32F103的操作实录,我个人是个小白,在学习过程中真的也遇到了不少坑,因此我希望能记录下来,帮助到同样踩坑的你。 我的芯片是GD32F103ZE,软件是Keil,烧写用的是JLink。 材料准备 首先我在兆易创新官网(兆易创新),下载相关的文件。点击资料下载,在搜索框里输入“GD32F10”可以得到相关的资料,其他芯片类似。比较重要的是GD32F10x AddOn和GD32F10x Firmware Library(固件库),这两个必须下载。 下载Keil MDK5,这

qq_41208487的博客 3万+

Modern C++ Design 笔记 第四章 Small-Object Allocation

在频繁的new/delete的时候容易衍生memory fragment, 我想设计这个Allocator的初衷就在这里。初看到这个题目的时候不由的让人联想到的东西是std::allocator.  所以我们就从MS的STL中看看std::allocator的实现。templateclass _Ty> inline    _Ty _FARQ *_Allocate(_SIZT _Coun

斯巴达的勇士已经是雅典的臣民了。。。 2552

Linux与Windows双系统,安装完linux后无法通过grub进入Windows的解决方法

先装Windows 10,Windows可正常启动,再装Kali,Kali提示装grub后照装。然而装完后重启发现无Windows选项。

sakurashockwave的博客 6454

chrome/chromium 上的内存管理模块-allocator介绍

本文介绍chromium在不同平台上 malloc/new 是如何封装调用的。 从代码中很容易发现,chromium的基础代码并不是仅仅使用“malloc”来分配内存 例如:         renderer(Blink)大部分都是用chromium单独设计的PartitionAlloc和BlinkGC(Oilpan)         像javascript引擎V8这样比较独立的子系统使用自己的...

鸿儒客栈 4532

RFSoC应用XCZU47DR八发八收FPGA设计方案

本文介绍了基于Xilinx XCZU47DR RFSoC芯片的八发八收FPGA设计方案。该方案采用集成射频数据转换器的SoC架构,支持8路14bit ADC(5GSPS)和8路14bit DAC(9.85GSPS),可直接处理5GHz以下射频信号。硬件设计包含高性能输入缓冲器、QMC校正和复杂混频器,适用于5G/6G通信、雷达、卫星通信等领域。文章详细阐述了ADC/DAC子系统参数,包括通道配置、采样率、带宽等特性,并提供了FPGA顶层模块的硬件接口设计,展示了多通道数据收发处理能力。该方案无需外置混频器,

toonyhe的博客 1790

遗传算法优化光学超表面:智能设计突破纳米结构瓶颈

光学超表面设计本质上是一个高维、非线性、离散每个结构单元(如纳米砖柱、孔洞、十字架)有多个参数(长、宽、高、旋转角、材料),整个阵列的参数组合数量随单元数指数级增长。性能指标(如聚焦效率、工作带宽、偏振转换率、特定角度响应)往往无法用简单解析式表达,需依赖计算密集型电磁仿真(如FDTD, FDFD, RCWA)来评估。结构参数微小变化可能引起光学响应的剧烈跃变,目标函数存在多个局部最优解。实际制造通常要求结构参数取自有限的离散值(如特定刻蚀深度、材料库)。

weixin_51101456的博客 1142

虚拟机内存管理之内存分配器

本文意在通过深入剖析常用的内存分配器的关键实现,以理解虚拟机动态内存管理的设计哲学,并为实现虚拟机高效的内存管理提供指引。

YZcoder的博客 2591

FPGA控制DDR读写(AXI4总线接口)

FPGA控制DDR读写

qq_42712308的博客 1万+

Small Object Detection via Coarse-to-fine Proposal Generation and Imitation Learning

在每一个阶段,之前的区域建议作为输入,在特征图上进行进一步的回归和优化,使得每个阶段的区域建议越来越精确。锚点:是一些预定义的边界框,它们在图像的不同位置和不同尺度上进行采样,以捕捉可能的目标,完善锚点的过程是对这些预定义的锚点进行调整和优化,使它们更准确地匹配图像中实际目标的大小和位置。在被认为具有视觉真实性的达吾提的引导下,解析还原尺寸受限实例的特征。1.我们建立了一个名为CRPN的从粗到细的建议生成通道,用于执行从锚点到建议的程序,其中基于区域的锚点挖掘策略和级联回归技术为小实例提供了高质量的建议。

w_gun的博客 1763

基于深度残差U-Net与多尺度注意力机制的医学图像分割系统

本文提出了一种创新的医学图像分割系统,通过融合残差连接、通道注意力机制和空间金字塔池化技术,构建了高性能的UResnet分割网络。系统采用编码器-解码器架构,创新性地引入多层次特征增强模块,显著提升了医学图像中复杂组织结构的分割精度。实验结果表明,该方案在多个医学图像数据集上均取得了优异性能,边界分割精度提升15%,训练收敛速度提升30%,同时减少20%计算量。系统为临床诊断提供了可靠的技术支持,未来可扩展至3D医学图像分割和联邦学习等方向。

Henry的博客 814

Ethercat学习-从站源码生成

移植平台GD32F450,从站芯片AX58100

西澳峰的博客 9224

侯捷老师 C++内存管理-第四讲 学习笔记

侯捷老师 C++内存管理-第四讲 Loki :: allocator

weixin_56042518的博客 488

【Tessent Shell Users Manual】【Ch3】Design Introspection and Editing(未完待续)

Tessent Shell 提供了一系列用于检查(examining/introspecting)和编辑design的命令。

Tranquil_ovo的博客 1731

小对象的分配技术(4/4)

4.SmallObject小对象分配策略在SmallObjAllocator层已经柳暗花明,可以猜测SmallObject是个顶级包装,使得使用更方便,确实是这样的,“SmallObject的定义 非常简单,只不过情节有点复杂”。class SmallObject...{public:    static    void*    operator new(std::size_t    

win2ks 999

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

第四章(小型对象分配技术:smart-object allocation)

分配原理 block:最小单位,外部指定,一般每个block从4~64byte不等。我们称为blocksize chunk:包含多个block。个数我们称为blocknum。每个chunk大小为blocknum*blocksize。一般为固定,大小我们称为page fixedAllocator:包含多个chunk。里面的chunk的block大小都是固定的。即每个fixedAllocator

920

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

一个支持线程安全的模板方式实现的内存分配器

<br />    这是我将云风书中的内存分配器用模板方式实现的,锁是windows的,换成Linux的很容易。可以单独使用CSmallObject_Allocator作为内存分配器,也可以让你的类CA继承SSmall_Alloc,这样“new CA”就会调用该内存分配器来分配内存,很方便。<br /> <br />inline size_t _min(size_t a, size_t b)<br />{<br /> return a<b?a:b;<br />}<br />template< bool bT

sigh667的专栏 675

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

小目标检测small object detection

整理了两个github上两个罗列近期small object detection相关工作的链接。 第一个链接:https://github.com/kuanhungchen/awesome-tiny-object-detection 这个链接的title是tiny object,估计只有我这个小聪明能找到,这个链接比较推荐,罗列的工作都是一些较好的会议和期刊上的工作。 第二个链接:https://github.com/ispc-lab/SmallObjectDetectionList 这个链接的

carlous0的专栏 2262

loki库之内存池SmallObj

[原创]loki库之内存池SmallObj http://www.cnblogs.com/UnGeek/p/4537114.html loki库之内存池SmallObj 介绍 loki库的内存池实现主要在文件smallobj中,顾名思义它的优势主要在小对象的分配与释放上,loki库是基于策略的方法实现的,简单的说就是把某个类通过模板参数传递给主类,比如某

zdy0_2004的专栏 1812

深度学习笔记 Augmentation for small object detection(翻译)

一. abstract 二. Introduction 三. Related Work 三. Identifying issues with detecting small objects 四. Identifying issues with detecting small objects 五. Experimental Setup 六. Result and Analysis 六. Conclusion References 一. abstract   这些年来,目标检测取得了令人瞩目的成就。尽管改进很大

weixin_44836143的博客 819

基于前面内存分配器的STL内存分配器

<br />    使用起来很简单,像这样:<br />typedef std::list< int, std::SR_allocator<int> >   IntList;<br />typedef std::set< INT, std::less<INT>, std::SR_allocator<INT> > IntAttrRefreshArray;<br />typedef std::map< int, CItemBoxRef*, std::less<int>, std::SR_allocator< s

sigh667的专栏 685

用未公开的MFC类加强动态内存分配

 用未公开的MFC类加强动态内存分配           下面是示例程序使用及未使用这个未公开MFC类的对比情况截图,是不是有点心动了呢,接着往下看。            简介         如果你经常浏览MFC的源代码,说不定就会有意想不到的惊喜发现,这不,很快就发现了一个,它是一个小工具类的集合,允许为特定类的对象定义怎样为其动态分配内存,这个类就是CF

谢启东的专栏 2431

小型对象内存分配

c++语法中动态分配和指针/引用的使用非常普遍,然而缺省的自由存储区分配器(比如::operator new和::operator delete)只适用于大对象对分配,对小对象分配并不有效,甚至非常低劣,多次分配小对象后容易产生碎片。  小型对象分配器小型对象分配器分为4层结构。如图所示,下层提供功能供上层使用。+-------------------+|    SmallOb

AngelTempt的专栏 992

【文献阅读】Perceptual Generative Adversarial Networks for Small Object Detection –CVPR-2017

Perceptual Generative Adversarial Networks for Small Object Detection 2017CVPR 新鲜出炉的paper,这是针对small object detection的一篇文章,采用PGAN来提升small object detection任务的performance。 最近也没做object detecti...

weixin_34185364的博客 765

小目标检测--A closer look: Small object detection in Faster R-CNN

A closer look: Small object detection in Faster R-CNN Improving Small Object Proposals for Company Logo Detection这里主要分析 Faster R-CNN 对小目标检测的性能分析及改进。 主要是 多尺度 RPN 和多尺度分类网络 数据中目标尺寸分布 3.1 Region Proposa

AI小作坊 的博客 6112

SOD-MTGAN: Small Object Detection via Multi-Task Generative Adversarial Network

SOD-MTGAN: Small Object Detection via Multi-Task Generative Adversarial Network 基于多任务GAN的细小物体检测 摘要 物体检测是计算机视觉中的一个基本而重要的问题。虽然在大规模检测基准(例如COCO数据集)中对大/中型物体取得了令人印象深刻的结果,但小物体的性能远远不能令人满意。原因是小物体缺乏足够详细的外观信息...

木盏 7151
上一篇: assert实作
下一篇: url ssl
daeees
博客等级 码龄19年 6粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值