如果按存储的地方来分类,缓存分为哪些?
分为本地缓存和分布式缓存。本地缓存就是把数据保存应用程序所在的那台机器的内存中;而分布式缓存是把数据放在缓存服务器中,这个缓存服务器有可能是和应用服务器在同一台机器,这时候的是跨进程访问,如果缓存服务器和应用程序服务器不在同一台机器,这时候就可能会设计到跨域跨进程访问了。
缓存通过何种方式来找到缓存中的数据?
表面上是通过键来找到对象,实际是通过对象的引用在内存中查找到数据对象的。
修改缓存对象和修改数据库数据是一回事吗?
千万不要认为修改缓存对象就是修改了数据库中对应的数据。如果修改的是本地缓存对象,那只是修改更新了内存的那个缓存对象。而对于分布式缓存,在应用程序中修改完缓存对象,还需要把新的对象数据传给跨域、跨进程之外的缓存服务器。
有哪些分布式缓存机制?
比如memcached,AppFabric......
分布式缓存保存和读取数据的大致过程是怎样的?
缓存数据的时候,使用API,在应用程序服务器上把数据序列化为字节,再把这些字节发送给缓存服务器,让其保存;读取缓存数据的时候,缓存服务器把对象对应的字节发送给应用程序,在应用程序服务器上的对应类库再把字节转换成对象。
.NET本地缓存有哪几种方式?
一种是给类打上Serializable特性,不过这种方式由于其内部使用了反射机制,会比较耗CPU,特别是处理大对象的时候;另一种方式是给类打上Serializable特新,并且还让这个类实现ISerializable接口,这种方式没有使用反射,效率是上一种方式的几百倍。
什么是缓存大对象?
当缓存对象占用的内存大于85K的时候,就把其认为是缓存大对象。注意,大于85*1024个字节是大对象,一个对集合的引用,比如List<Person> list = new List<Person>(),其中list只是指向托管堆上的一个引用,不是大对象。
大对象与内存碎片,内存碎片是如何产生的?
大对象是被放在托管堆上的大堆上的,当GC进行垃圾回收后,大堆是不会被压缩的。内存碎片的产生大致这样:
→产生大对象
→在内存空间为该大对象开辟一块连续的区域
→CLR的GC进行垃圾回收,对象被回收,内存上该对象对应的大堆没有被压缩,这块内存空间还一直存在的
→在产生一个比第一次小的对象,占用刚才大堆内存空间的一部分
→于是,剩下的大堆内存空间的那部分成了碎片
线程间共享缓存数据会造成冲突吗?
答案是会的。
monospace; width: 100%; margin: 0em; background-color: #f0f0f0">......int a = 0;myCache["mykey"] = 0;var thread1 = new Thread(new ThreadStart(() =>{a = myCache["mykey"];a++;myCahce["mykey"]=a;}));var thread2 = new Thread(new ThreadStart(() =>{a = myCache["mykey"];a++;myCahce["mykey"]=a;}));thread1.Start();thread2.Start();
最终的结果可能是0也可能是1。
调用缓存API把数据缓存起来后,就一定能读取到吗?
不一定。因为缓存机制一般设置绝对或相对过去时间,一旦过了这个时间,缓存数据就没有了。另外,缓存服务器CPU忙、网络不好也会导致数据没有被即时序列化保存到缓存服务器中。
所以,每次使用缓存数据的时候,先要判断缓存数据是否存在。
参考资料:汪洋的"DotNet"公众号。