裸指针和智能指针的性能对比

本文比较了裸指针和智能指针的性能

1.unique_ptr与queue连用,unique_ptr的使用特点:不能使用拷贝构造函数,拷贝赋值函数,但是可以使用move构造函数和move赋值函数。

2.std::move的使用,可以将左值表达式强制转化成为右值表达式

3. 重载new操作符调试内存使用情况,因为心里不是很放心(智能指针真的为我释放了内存么?)所以尝试了重写new delete操作符。

4. 得到的结果是raw_ptr:unique_ptr:shared_ptr的性能是5:7:11,可见智能指针的效率还是相当诱人。

#include <iostream>
#include <memory>
#include <Windows.h>
#include <queue>
#include <Psapi.h>
using namespace std;

static size_t	s_my_int_count = 0;
const  int		MAX_LOOP_ = 3000000;

const int      NORMAL_FLAG = 0x12ff0101;
const int	   MY_INT_FLAG = 0x12ff0102;

void* operator new(std::size_t size)throw(std::bad_alloc)//重写new操作符为的是统计我们关心的内存分配
{
	int addLen = sizeof(size_t);
	void * p = std::malloc(addLen + 4 + size) ;

	if (!p)
		throw std::bad_alloc() ;

	memcpy(p, &size, addLen);//标志实际长度
	memcpy((char*)p + addLen, &NORMAL_FLAG, 4);//标志类型,普通---0x12ff0101, 我自己的int---0x12ff0102, 我自己的char[]---0x12ff0103
	return ((char*)p + addLen + 4);
}

void* operator new(std::size_t size, int flag)throw(std::bad_alloc)// 对应于调用 “new(MY_INT_FLAG) int” 这样所有我们关心的内存多可以被监视
{
	int addLen = sizeof(size_t);
	void * p = std::malloc(addLen + 4 + size) ;

	if (!p)
		throw std::bad_alloc() ;

	if (flag == MY_INT_FLAG){
		s_my_int_count ++;//统计关心的内存申请次数
	}

	memcpy(p, &size, addLen);//标志实际长度
	memcpy((char*)p + addLen, &flag, 4);//放置标志位,标志类型,普通---0x12ff0101, 我自己的int---0x12ff0102, 我自己的char[]---0x12ff0103
	return ((char*)p + addLen + 4);
}

void operator delete(void * q) throw()
{
	void* p;
	int addLen = sizeof(size_t);
	p = (char*)q - addLen - 4;//还原原来的指针位置,p是真正的系统malloc出来的指针
	int flag;
	memcpy(&flag, (char*)p + addLen, 4);//得到标志位
	
	if (flag == MY_INT_FLAG){//统计关心的内存释放次数
		s_my_int_count --;
	}

	if (p)
		std::free(p) ;
}

void main(){
	queue<int*>  intQueue;
	int count = 0;

	count = 0;

	cout << "before push " << s_my_int_count << " int allocated"<< endl;
	LONGLONG start = GetTickCount();
	for (int i = 0; i < MAX_LOOP_; i ++)
	{
		int* p = new(MY_INT_FLAG) int;
		intQueue.push(p);		
	}
	cout << "after push " << s_my_int_count << " int allocated"<< endl;
	while (!intQueue.empty()){
		int* p = intQueue.front();
		intQueue.pop();
		delete p;//注意需要手动释放
		count ++;
	}
	cout << "after pop " << s_my_int_count << " int allocated"<< endl;
	cout << "===================raw int ptr for " << count << "\t" << GetTickCount() - start << endl;


	unique_ptr<int> q(new int);
	unique_ptr<int> r = move(q);// 编译正确,r(q) 和 r = q则编译失败,因为unique_ptr已经不允许使用“拷贝构造函数”

	queue<unique_ptr<int>> intUniQueue;//因为unique_ptr没有“拷贝构造函数”  copy-constructor
	//所以push()的参数不能是“左值”,左值会调用“拷贝构造函数”
	//只能是“右值”,右值则会调用“移动构造函数” move-constructor,  
	//std::move()函数可以强制将左值转化成为右值

	count = 0;
	start = GetTickCount();	
	cout << "before push " << s_my_int_count << " int allocated"<< endl;
	for (int i = 0; i < MAX_LOOP_; i ++)
	{
		unique_ptr<int> p(new(MY_INT_FLAG) int);
		intUniQueue.push(std::move(p));//因为p不是“右值”,所以我们需要“显式”的调用move将p强制转为右值。
	}
	cout << "after push " << s_my_int_count << " int allocated"<< endl;
	while (!intUniQueue.empty()){
		unique_ptr<int> p = std::move(intUniQueue.front());//queue.front() 是一个左值引用,即queue.front()=2 合法。
		intUniQueue.pop();
		count ++;
	}
	cout << "after pop " << s_my_int_count << " int allocated"<< endl;
	cout << "===================int unique  ptr for " << count << "\t" << GetTickCount() - start << endl;

	queue<shared_ptr<int>> intSharedQueue;
	count = 0;
	start = GetTickCount();	
	cout << "before push " << s_my_int_count << " int allocated"<< endl;
	for (int i = 0; i < MAX_LOOP_; i ++)
	{
		shared_ptr<int> p(new(MY_INT_FLAG) int);
		intSharedQueue.push(p);
	}
	cout << "after push " << s_my_int_count << " int allocated"<< endl;
	while (!intSharedQueue.empty()){
		auto p = intSharedQueue.front();
		intSharedQueue.pop();		
		count ++;
	}
	cout << "after pop " << s_my_int_count << " int allocated"<< endl;
	cout << "===================int shared ptr for " << count << "\t" << GetTickCount() - start << endl;

}

/*
智能指针省去了我们释放指针的精力,但是也需要一定的开销。unique_ptr 的开销相对于shared_ptr要小很多。
如果一个资源每个时刻都只要有一个支配者,我们还是优先使用unique_ptr吧,效率会高很多。

before push 0 int allocated
after push 3000000 int allocated
after pop 0 int allocated
===================raw int ptr for 3000000      5375
before push 0 int allocated
after push 3000000 int allocated
after pop 0 int allocated
===================int unique  ptr for 3000000  7313
before push 0 int allocated
after push 3000000 int allocated
after pop 0 int allocated
===================int shared ptr for 3000000   11171
请按任意键继续. . .
*/


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 平台上的智能指针是一种用于管理对象生命周期的工具。在 Java 开发中,Java 虚拟机(JVM)通过垃圾回收机制自动管理对象的内存释放,但在某些情况下,手动进行对象的释放和管理可能是必要的,以避免内存泄漏和资源浪费。 在 Android 开发中,最常用的智能指针是弱引用(WeakReference)和软引用(SoftReference)。这两种指针都可以用来引用对象,但是它们具有不同的特性。 弱引用是一种比较短暂的引用,当对象只有弱引用指向时,即使内存不足,垃圾回收机制仍然会释放该对象。这使得弱引用特别适合处理一些临时性的对象,比如缓存中的数据。在 Android 中,可以使用 WeakReference 类来创建和管理弱引用。 软引用则相对于弱引用更加持久,当内存不足时,垃圾回收机制可能会释放被软引用指向的对象。软引用适合于缓存一些占用内存较大的对象,当内存不足时可以释放这些对象以避免 Out of Memory 错误。在 Android 中,可以使用 SoftReference 类来创建和管理软引用。 除了弱引用和软引用,Android 还提供了其他一些智能指针类,如 PhantomReference 和 FinalizerReference,用于更灵活地管理对象的生命周期。 需要注意的是,尽管使用智能指针可以帮助更好地管理对象的生命周期,但过度使用智能指针可能会导致性能问题。因此,在使用智能指针时,需要根据具体情况慎重考虑,并在必要时手动释放对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值