一次堆外OOM问题的排查过程

转载自   一次堆外OOM问题的排查过程

背景

线上服务有一台机器访问不通(一个管理平台),在公司的服务治理平台上查看服务的状况是正常的,说明进程还在。进程并没有完全crash掉。去线上查看机器日志,发现了大量的OOM异常:

017-03-15 00:00:00.041 [WARN] qtp1947699202-120772 nio handle failed
java.lang.OutOfMemoryError: Direct buffer memoryat java.nio.Bits.reserveMemory(Bits.java:658) ~[?:1.7.0_76]at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) ~[?:1.7.0_76]at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306) ~[?:1.7.0_76]at sun.nio.ch.Util.getTemporaryDirectBuffer(Util.java:174) ~[?:1.7.0_76]at sun.nio.ch.IOUtil.read(IOUtil.java:195) ~[?:1.7.0_76]at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:379) ~[?:1.7.0_76]at org.eclipse.jetty.io.nio.ChannelEndPoint.fill(ChannelEndPoint.java:235) ~[jetty-io-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.io.nio.SelectChannelEndPoint.fill(SelectChannelEndPoint.java:326) ~[jetty-io-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.http.HttpParser.fill(HttpParser.java:1040) ~[jetty-http-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:280) ~[jetty-http-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) ~[jetty-http-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82) ~[jetty-server-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:628) [jetty-io-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52) [jetty-io-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) [jetty-util-8.1.10.v20130312.jar:8.1.10.v20130312]at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) [jetty-util-8.1.10.v20130312.jar:8.1.10.v20130312]at java.lang.Thread.run(Thread.java:745) [?:1.7.0_76]at java.lang.Thread.run(Thread.java:745) [?:1.7.0_76]2017-03-15 00:00:00.718 [WARN] elasticsearch[Thundra][transport_client_worker][T#6]{New I/O worker #6} AbstractNioSelector Unexpected exception in the selector loop.
java.lang.OutOfMemoryError: Direct buffer memoryat java.nio.Bits.reserveMemory(Bits.java:658) ~[?:1.7.0_76]at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) ~[?:1.7.0_76]at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306) ~[?:1.7.0_76]at org.jboss.netty.channel.socket.nio.SocketReceiveBufferAllocator.newBuffer(SocketReceiveBufferAllocator.java:64) ~[netty-3.10.5.Final.jar:?]at org.jboss.netty.channel.socket.nio.SocketReceiveBufferAllocator.get(SocketReceiveBufferAllocator.java:41) ~[netty-3.10.5.Final.jar:?]at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:62) ~[netty-3.10.5.Final.jar:?]at org.jboss.netty.channel.socket.nio.AbstractNioWorker.process(AbstractNioWorker.java:108) ~[netty-3.10.5.Final.jar:?]at org.jboss.netty.channel.socket.nio.AbstractNioSelector.run(AbstractNioSelector.java:337) [netty-3.10.5.Final.jar:?]at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:89) [netty-3.10.5.Final.jar:?]at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:178) [netty-3.10.5.Final.jar:?]at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) [netty-3.10.5.Final.jar:?]at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:42) [netty-3.10.5.Final.jar:?]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [?:1.7.0_76]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [?:1.7.0_76]at java.lang.Thread.run(Thread.java:745) [?:1.7.0_76]

可以发现是Direct buffer memory的native memory满了,无法分配堆外内存。由于jetty使用的是nio,nio里面大量的使用native memeory。无法分配native memory之后,导致所有的请求都无效

排查

赶快去看了下监控系统上面内存和线程的一些监控指标

 


 


 

 

 

文件描述符、runable线程数 、directbuffer 已经达到了2G(我们-Xmx的值),老年代已经1G多了。但是没有fullGC。youngc次数也不是很多,但是出现问题的机器young gc明显比没出现问题的机器多

根据上面的指标,初步定位是由线程创建的网络连接造成了native memory不够 。最上面的log日志显示除了jetty之外还有一个就是ElasticSearch client的worker线程也出现的分配OOM。回想上次开发新功能的时候,会创建大量的ES client连接,会不会是这个问题。查看代码发现确实是因为创建了大量的ES连接,但是并没有主动close掉。导致线程数暴增,由于ElasticSearch client是用的netty做的网络层,使用了大量的DirectByteBuffer.引用一直存在(client线程一直存在),无法GC掉,DirectByteBuffer对象,导致native memory也无法回收。下图是用jprofile测试ElasticSearch client的时候发现的。可以得到的是ElasticSearch client确实会产生大量的DirectByteBuffer

 

old gen为什么会多呢?

那为什么old gen的对象这么多呢?其实就是一大堆的bytebuffer冰山对象进入了oldgen ,然而fullgc都没有发生,bytebuffer不会被回收,但是这个时候native memory已经被分配完了,所以OOM了。查了资料发现我们在JVM参数中添加了这个:-XX:+DisableExplicitGC.这个参数会导致显示调用System.gc()无效。然而在分配native memory中有这样一段代码:

// These methods should be called whenever direct memory is allocated or
// freed.  They allow the user to control the amount of direct memory
// which a process may access.  All sizes are specified in bytes.
static void reserveMemory(long size, int cap) {synchronized (Bits.class) {if (!memoryLimitSet && VM.isBooted()) {maxMemory = VM.maxDirectMemory();memoryLimitSet = true;}// -XX:MaxDirectMemorySize limits the total capacity rather than the// actual memory usage, which will differ when buffers are page// aligned.if (cap <= maxMemory - totalCapacity) {reservedMemory += size;totalCapacity += cap;count++;return;}}//提醒jvm该gc了,回收下死掉的对象System.gc();try {Thread.sleep(100);} catch (InterruptedException x) {// Restore interrupt statusThread.currentThread().interrupt();}synchronized (Bits.class) {//计算可分配的是否已经超过maxMemeory,超过则抛出OOM异常if (totalCapacity + cap > maxMemory)throw new OutOfMemoryError("Direct buffer memory");reservedMemory += size;totalCapacity += cap;count++;}}

通过这段代码发现,每次分配native memory的时候会通知jvm进行一次GC。如果我们配置了上面的jvm参数会导致这行代码不起任何作用。old gen里面的对象就算死掉也不会回收,除非old gen本身满了,但是通过上面的old gen使用了1G,还没有到old gen的最大值。没有full gc所以native memory一直没有被回收。其实就算我们没有设置jvm参数估计也会OOM ,因为bytebuffer因为线程只有的关系不会全部死掉。大部分bytebuffer也不会被回收

关于DirectByteBuffer

 

  • Perm中主要放一些class和meta信息,常量池,静态字段等。这些东西都放在所谓的方法区中,在hotspot中也就是“持久带”。
  • 对于习惯在HotSpot虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已
  • 用-Xmx -Xms -Xmn 指定堆的最大值、初始值、和年轻带的大小,由上图可知young区也分为Eden 、from 、to上个区,比例默认是8:1:1 可以用-XX:SurvivorRatio设置年轻代中Eden区与Survivor区的大小比值
  • 堆内内存由JVM gc统一管理回收,关于垃圾回收算法,这里不再赘述

堆外内存(off-heap memory)

和堆内内存相对应,堆外内存就是把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机),这样做的结果就是能够在一定程度上减少垃圾回收对应用程序造成的影响。堆外内存默认是和-Xmx默认一样大,也可以使用-XX:MaxDirectMemorySize指定堆外内存大小

作为JAVA开发者我们经常用java.nio.DirectByteBuffer对象进行堆外内存的管理和使用,它会在对象创建的时候就分配堆外内存。DirectByteBuffer类是在Java Heap外分配内存,对堆外内存的申请主要是通过成员变量unsafe来操作。关于Cleaner回收native memory又是另一个重要的点了。比如:为什么不用finalize来回收native memory。另外找机会写.

我们可以知道的是,随着DirectByteBuffer被GC掉之后,被分配的native memory会被回收

DirectByteBuffer(int cap) {                super(-1, 0, cap, cap);//内存是否按页分配对齐boolean pa = VM.isDirectMemoryPageAligned();//获取每页内存大小int ps = Bits.pageSize();//分配内存的大小,如果是按页对齐方式,需要再加一页内存的容量long size = Math.max(1L, (long)cap + (pa ? ps : 0));//用Bits类保存总分配内存(按页分配)的大小和实际内存的大小Bits.reserveMemory(size, cap);long base = 0;try {//在堆外内存的基地址,指定内存大小base = unsafe.allocateMemory(size);} catch (OutOfMemoryError x) {Bits.unreserveMemory(size, cap);throw x;}unsafe.setMemory(base, size, (byte) 0);//计算堆外内存的基地址if (pa && (base % ps != 0)) {// Round up to page boundaryaddress = base + ps - (base & (ps - 1));} else {address = base;}//当this对象即directByteBuffer被gc回收时,释放native memory(为什么不用)cleaner = Cleaner.create(this, new Deallocator(base, size, cap));att = null;
}private static class Deallocator implements Runnable  {private static Unsafe unsafe = Unsafe.getUnsafe();private long address;private long size;private int capacity;private Deallocator(long address, long size, int capacity) {assert (address != 0);this.address = address;this.size = size;this.capacity = capacity;}public void run() {if (address == 0) {// Paranoiareturn;}//回收native memoryunsafe.freeMemory(address);address = 0;Bits.unreserveMemory(size, capacity);}
}

我们知道了回收堆内的DriectByteBuffer就会回收native memory,出现OOM的情况就是native memory被分配完了。也同时因为这个原因,假设进入Old gen的对象本来已经死了,但是并没有full gc回收,native memory不能被及时回收。为了避免这种情况,在分配DirectByteByffer的时候会主动调用一次System.GC().通知JVM进行一次full gc。定期清理堆中的垃圾,及时的释放native memory。堆外内存溢出

但是用了-XX:+DisableExplicitGC参数后,System.gc()的调用就会变成一个空调用,完全不会触发任何GC(但是“函数调用”本身的开销还是存在的).为啥要用这个参数呢?最主要的原因是为了防止某些手贱的同学在代码里到处写System.gc()的调用而STW干扰了程序的正常运行吧。有些应用程序本来可能正常跑一天也不会出一次full GC,但就是因为有人在代码里调用了System.gc()而不得不间歇性被暂停。也有些时候这些调用是在某些库或框架里写的,改不了它们的代码但又不想被这些调用干扰也会用这参数。

但是如果使用堆外内存,同时使用了这个参数,比如同时满足下面3个条件,就很容易发生OOM

  1. 应用本身在GC堆内的对象行为良好,正常情况下很久都不发生full GC;
  2. 应用大量使用了NIO的direct memory,经常、反复的申请DirectByteBuffer
  3. 使用了-XX:+DisableExplicitGC

下面使用一些实例在看看在使用了DisableExplicitGC这个参数之后,到底会发生什么。

第一种:

native memory满了,但是young区没满,没有发生young gc回收DirectByteBuffer,所以堆外OOM(如果去掉DisableExplicitGC参数程序会一直有Full GC的信息输出,因为分配native memory的时候会主动调用System.GC())

-Xmx64m
-Xms64m
-Xmn32m
-XX:+UseConcMarkSweepGC
-XX:+PrintGCDetails
-XX:+DisableExplicitGC//限制GC限制调用
-XX:MaxDirectMemorySize=10M//堆外10M
int i =1;
while(true){System.out.println("第"+(i++)+"次");ByteBuffer byteBuffer = ByteBuffer.allocateDirect( 1024*1024);
}//输出
第10次
第11次//10M就分配满了,分配第11次的时候会OOM
Heappar new generation   total 29504K, used 3149K [0x00000007f6e00000, 0x00000007f8e00000, 0x00000007f8e00000)eden space 26240K,  12% used [0x00000007f6e00000, 0x00000007f7113578, 0x00000007f87a0000)//eden区只用了12%from space 3264K,   0% used [0x00000007f87a0000, 0x00000007f87a0000, 0x00000007f8ad0000)to   space 3264K,   0% used [0x00000007f8ad0000, 0x00000007f8ad0000, 0x00000007f8e00000)concurrent mark-sweep generation total 32768K, used 0K [0x00000007
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memoryat java.nio.Bits.reserveMemory(Bits.java:658)at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)

native memory没满,但是young区在native memory满之前提前满了,发生young gc回收DirectByteBuffer,不会发生OOM第二种:

如果代码换成了下面这种(jvm参数一样),一次分配的native memory足够小,会导致在native memory没有分配满的情况下,发生young gc会搜DirectByteBuffer。同时会回收native memory

ByteBuffer byteBuffer = ByteBuffer.allocateDirect( 1024/2/2/2/2/2);
//输出会有
[GC[ParNew: 29503K->3262K(29504K), 0.0369960 secs] 44757K->25060K(62272K), 0.0370220 secs] [Times: user=0.18 sys=0.00, real=0.04 secs]
...
...
Heap
//退出程序时会发现young区并没有满par new generation   total 29504K, used 12716K [0x00000007f6e00000, 0x00000007f8e00000, 0x00000007f8e00000)eden space 26240K,  36% used[0x00000007f6e00000, 0x00000007f773b530, 0x00000007f87a0000)from space 3264K,  99% used [0x00000007f8ad0000, 0x00000007f8dffbc0, 0x00000007f8e00000)to   space 3264K,   0% used

大量DirectByteBuffer对象移动到old gen。没有Full gc的发生,导致在程序中可能死掉的DirectByteBuffer对象没有回收掉,native memory则满了,发生OOM第三种:

-Xmx64m
-Xms64m
-Xmn32m
-XX:+PrintGCDetails
-XX:MaxTenuringThreshold=1//设置进去old gen的寿命是1,默认是15次才进入old gen
-XX:MaxDirectMemorySize=10M
-XX:+DisableExplicitGC//不能显示full gcint i = 1;
List<ByteBuffer> list = new ArrayList<ByteBuffer>();
while (true) {System.out.println("第" + (i++) + "次");ByteBuffer.allocate(1024 * 1024);//分配堆内内存ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024 / 2 / 2 / 2 );list.add(byteBuffer);//保证引用不被younggc}
//输出
[GC[ParNew: 25620K->6K(29504K), 0.0004310 secs] 38176K->12564K(62272K), 0.0004450 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//中途有一些young gc
//.....
//最终输出
Heap
//young 区也没有满PSYoungGen      total 32256K, used 26419K [0x000000010d700000, 0x000000010f700000, 0x000000010f700000)eden space 31744K, 82% used [0x000000010d700000,0x000000010f0a4c70,0x000000010f600000)from space 512K, 31% used [0x000000010f680000,0x000000010f6a8000,0x000000010f700000)to   space 512K, 0% used [0x000000010f600000,0x000000010f600000,0x000000010f680000)
//old gen 已经用了62%了ParOldGen       total 32768K, used 20586K [0x000000010b700000, 0x000000010d700000, 0x000000010d700000)object space 32768K, 62% used [0x000000010b700000,0x000000010cb1a908,0x000000010d700000)PSPermGen       total 21504K, used 3097K [0x0000000106500000, 0x0000000107a00000, 0x000000010b700000)object space 21504K, 14% used [0x0000000106500000,0x00000001068065e8,0x0000000107a00000)

如果你在使用Oracle/Sun JDK 6,应用里有任何地方用了direct memory,那么使用-XX:+DisableExplicitGC要小心。如果用了该参数而且遇到direct memory的OOM,可以尝试去掉该参数看是否能避开这种OOM

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324099.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Azure与Scott Guthrie:Azure安全中心和基于角色的访问控制

InfoQ有幸采访了Microsoft执行副总裁Scott Guthrie&#xff0c;请他谈了谈Azure以及他最近的Red Shirt Dev Tours&#xff08;红杉开发之旅&#xff09;【译注1】。昨天我们谈到了Azure提供了自定义仪表盘的功能&#xff0c;它能够使得开发者创建自定义工作任务流程&#xff0c…

什么时候才能都及格呢?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。今天是周五&#xff0c;又到了周测的时候了&#xff0c;发现现在考试&#xff0c;学生们的抵触情绪不会那么强烈了&#xff0c;以前只要一说啥时啥时考试&#xff0c;下面一片哀嚎声&#xff0c;各种不…

解决Visual Studio For Mac Restore失败的问题

之前就了解到微软出了mac版的VS&#xff0c;没太多的关注&#xff0c;自己也就是使用 DotNet Core SDK VS Code 做一些小demo。 前两天发布了DotNet Core 2.0 &#xff0c;Visual Studio For Mac 7.1 之后&#xff0c;感觉可以装起来用用&#xff0c;把win下面的项目转到Core…

来之不易的美团面试,结果居然挂了...(附面试答案)

转载自 来之不易的美团面试&#xff0c;结果居然挂了...&#xff08;附面试答案&#xff09; 一面 自我介绍 答&#xff1a;自我介绍是面试中唯一的自己主动介绍自己的环节&#xff0c;一定要好好把握好&#xff0c;你数据结构学的号可以手撕一个红黑树你就说我数据结构掌握…

三班的孩子们,你们现在还好吗?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。三班的孩子们&#xff0c;你们还好吗&#xff1f;虽然已经就业&#xff0c;但还是会时不时的想起你们来&#xff0c;希望你们过的一切都好&#xff0c;在公司中也能快速适应。上午拿着电脑准备去四班上…

升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署

概述 容器&#xff0c;顾名思义是用来存放并容纳东西的器皿&#xff1b; 而容器技术伴着Docker的兴起也渐渐的映入大家的眼帘&#xff0c;它是一个抽象的概念&#xff0c;同时也是默默存在世上多年的技术&#xff0c;不仅能使应用程序间完全的隔离&#xff0c;而且还能在共享…

Spring Data Elasticsearch

文章目录一、 ELK二、 Elasticsearch简介三、 Linux安装Elasticsearch四、SpringData Elasticsearchpom.xmlapplication.yml创建实体创建索引 设置映射简单增删改查搜索五、 LogStash六、 使用Logback向Logstash中输出日志七、 在Kibana中查看日志信息八、 搭建日志系统九、 在…

项目参与度较低怎么办?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注公众号【雄雄的小课堂】。经过这两天做项目的表现&#xff0c;可以很明显的看的出来学生与学生之间掌握的还是有差距的&#xff0c;组内有的组员是可以为项目贡献代码的&#xff0c;但是有的组员可能只能是贡献素材&#xff0c;…

从 TFS 迁移源代码到 git

准备工具&#xff1a; https://github.com/git-tfs/git-tfs 具体的安装步骤上面的 readme.md 中有说明。通过 Chocolatey 安装&#xff0c;如果本地没有 git &#xff0c;会自动安装 git 到本地。 迁移步骤&#xff1a; 从 Visual Studio 里面进入 Source Control Explorer…

缓存穿透、缓存并发、缓存失效之思路变迁

转载自 缓存穿透、缓存并发、缓存失效之思路变迁 在用缓存的时候&#xff0c;基本上会通用遇到以下三个问题&#xff1a; 缓存穿透缓存并发缓存失效 一、缓存穿透 上面三个图会有什么问题呢&#xff1f; 我们在项目中使用缓存通常都是先检查缓存中是否存在&#xff0c;如果…

jzoj3792,P2062-分队问题【贪心】

前言 题解上说&#xff1a; 然而我的贪心不仅A了&#xff0c;而且 反例也A了 自己的洛谷题解链接&#xff1a;https://www.luogu.org/blog/user52918/solution-p2062 正题 大意 n个人&#xff0c;每个人有一个要求a[i]表示他所在的队伍里不可以少于a[i]个人&#xff0…

.net core 2.0学习笔记(二):Hello World amp;amp; 进阶

官网已经有一个.net core的入手教程&#xff08;https://www.microsoft.com/net/core#windowscmd&#xff09;&#xff0c;但这个教程完全没有顾及全宇宙第一IDE的感受。今天就跟大家体验一下在VS2017上开发.net core程序吧。VS2017开发环境的搭建请参考&#xff1a;http://www…

MyBatis】MyBatis一级缓存和二级缓存

转载自 MyBatis】MyBatis一级缓存和二级缓存 MyBatis自带的缓存有一级缓存和二级缓存 一级缓存 Mybatis的一级缓存是指Session缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。 也就是在同一个SqlSession中&#xff0c;执行相同的查询SQL&#xff…

.net core 2.0学习笔记(一):开发运行环境搭建

期待已久的.net core 2.0终于发布了&#xff01;大家等的花儿都谢了。 不过比预期提前了一个多月&#xff0c;这在微软历史上还真的不多见。按照历史经验看&#xff0c;2.0版本应该比较靠谱&#xff0c;我猜这也是社区非常火爆的原因吧。下面就简单分享一下.net core2.0开发运行…

不好意思,你这个加分理由不行……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。周五了&#xff0c;又该周测了&#xff0c;今天和以往一样&#xff0c;上午前两节课都在上课&#xff0c;第三节课进行测试&#xff0c;这周的填空题有点儿多&#xff0c;所以考试的时间较…

SQL索引一步到位

转载自 SQL索引一步到位 SQL索引在数据库优化中占有一个非常大的比例&#xff0c; 一个好的索引的设计&#xff0c;可以让你的效率提高几十甚至几百倍&#xff0c;在这里将带你一步步揭开他的神秘面纱。 1.1 什么是索引&#xff1f; SQL索引有两种&#xff0c;聚集索引和非聚…

jzoj3794,P1383-高级打字机【欧拉序,离线O(n)】

正题 题目链接&#xff1a;https://www.luogu.org/problemnew/show/P1383 大意 三个操作 T c&#xff1a;加入一个字符c U x&#xff1a;撤销前x次操作&#xff08;只包括T和U&#xff09; Q x&#xff1a;询问当前第x个字符 解题思路 对于50%的数据U不会撤销到U 所以我们可…

你也可以做一个简易抽奖程序!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。今天给大家分享一个使用winform制作的小案例——随机点名&#xff08;抽奖&#xff09;程序&#xff0c;下面我们来看看运行结果&#xff1a;在班内点名为了公平起见&#xff0c;一直使用的…

ASP.NET Core 2.0 特性介绍和使用指南

ASP.NET Core 2.0 发布日期&#xff1a;2017年8月14日 ASP.NET团队宣布ASP.NET Core 2.0正式发布&#xff0c;发布Visual Studio 2017 15.3支持ASP.NET Core 2.0&#xff0c;提供新的Razor Pages项目模板。 详细发布信息查看.NET Core 2.0.0发布说明文档 最新版SDK下载&…

blog项目中遇到的问题及解决

1、dependencesmangement 只做资源定位 2、多模块开发中mapper扫描 3、lambda表达式简写时&#xff08;使用lombox建造者模式&#xff09; 4、新增评论时 使用mp的自动填充时userid未赋值