`
leonzhx
  • 浏览: 803231 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Zz Garbage Collection in Java

    博客分类:
  • JVM
阅读更多

Heap Overview

 

This is the first in a series of posts about Garbage Collection (GC). I hope to be able to cover a bit of theory and all the major collectors in the hotspot virtual machine over the course of the series. This post just explains what garbage collection is and elements common to different collectors.

Why should I care?

Your Java virtual machine manages memory for you - which is highly convenient - but it might not be optimally tuned by default. By understanding some of the theory behind garbage collection you can more easily tune your collector. A common concern is collector efficiency, that is to say how much time your program spends executing program code rather than collecting garbage. Another common concern is how long that application pauses for.

There's also a lot of hearsay and folklore out there about garbage collection and so understanding the algorithms in a bit more detail really helps avoid falling into common pitfalls and traps. Besides - for anyone interested in how computer science principles are applied and used, JVM internals are a great thing to look at.

What does stop-the-world mean?

Your program (or mutator in GC-Speak) will be allocating objects as it runs. At some point your heap needs to be collected and all of the collectors in hotspot pause your application. The term 'stop-the-world' is used to mean that all of the mutator's threads are paused.

Its possible to implement a garbage collector that doesn't need to pause. Azul have implemented an effectively pauseless collector in their Zing virtual machine. I won't be covering how it works but there's a really interesting whitepaper if you want to know more.

The Young/Weak Generational Hypothesis

Simply stated: Most allocated objects die young 1. This concept was demonstrated by empirically analysing the memory allocation and liveness patterns of a large group of programs during the 1980s. What researchers found was that not only do most objects die young but once they live past a certain age they tend to live for a long time. The graph below is taken from a SUN/Oracle study looking at the lifespan of objects as a histogram.



 

How is Heap organised?

The young generational hypothesis has given rise to the idea of generational garbage collection in which heap is split up into several regions, and the placement of objects within each region corresponds to their age. One element that is common to the above these garbage collectors (other than G1) is the way that heap is organised into different spaces.



 

When objects are initially allocated, if they fit, they are stored in the Eden space. If the object survives a collection then it ends up in a survivor space. If it survives a few times (your tenuring threshold) then the object ends up in the tenured space. The specifics of the algorithms for collecting these spaces differs by collector, so I'll be covering them seperately in a future blog post.

This split is beneficial because it allows you to use different algorithms on different spaces. Some GC algorithms are more efficient if most of your objects are dead and some are more efficient if most of your objects are alive. Due to the generational hypothesis usually when it comes time to collect most objects in Eden and survivor spaces are dead, and most objects in tenured are alive.

There is also the permgen - or permanent generation. This is a special generation that holds objects that are related to the Java language itself. For example information about loaded classes is held here. Historically Strings that were interened or were constants were also held here. The permanent generation is being removed in favour of metaspace.

Multiple Collectors

The hotspot virtual machine actually has a variety of different Garbage Collectors. Each has a different set of performance characteristics and is more (or less) suited for different tasks. The key Garbage Collectors that I'll be looking at are:

  • Parallel Scavenge (PS): the default collector in recently released JVMs. This stops-the-world in order to collect, but collects in parallel (ie using multiple threads).
  • Concurrent Mark Sweep (CMS): this collector has several phases, some of which stop the world, but runs concurrently with the program for several of its phases as well.
  • Incremental Concurrent Mark Sweep (iCMS): a variant of CMS designed for lower pauses. It sometimes achieves this!
  • Garbage First (G1): a newish collector that's recently become more stable and is in slowly increasing usage.

Conclusions

I've given a few introductory points of thought about garbage collection, in the next post I'll be covering the Parallel Scavenge collector - which is currently the default collector. I'd also like to provide a link to my employer who have a GC log analyser which we think is pretty useful.

  1. "hotspot" is the name given to the codebase common behind openjdk and the official Oracle JVM. As of Java 7 openjdk is the reference implementation for Java SE.
  2. Technically what I described above is the 'weak generational hypothesis' which has empirical validation. There's also a strong variant which can be stated as The mean lifetime of a heap allocated object is equal to the mean amount of reachable storage. This is actually mathematically provable by taking Little's Law and setting Λ to 1. Simple proof!
  3. I'll cover the way heap is organised within G1 on a G1-specific blog post.

Parallel GC

 

Parallel Scavenge

Today we cover how Parallel GC works. Specifically this is the combination of running a Parallel Scavenge collector over Eden and the Parallel Mark and Sweep collector over the Tenured generation. You can get this option by passing in -XX:+UseParallelOldGC though its the default on certain machine types.

You may want to read my first blog post on Garbage Collection if you haven't since this gives a general overview.

Eden and Survivor Spaces

In the parallel scavenge collector eden and survivor spaces are collected using an approach known as Hemispheric GC. Objects are initially allocated in Eden, once Eden is close to full 1 a gc of the Eden space is triggered. This identifies live objects and copies them to the active Survivor Space2. It then treats the whole Eden space as a free, contiguous, block of memory which it can allocate into again.

In this case the allocation process ends up being like cutting a piece of cheddar. Each chunk gets sliced off contiguously and then the slice next to is the next to be 'eaten'. This has the upside that allocation merely requires pointer addition.



 

A slab of cheddar, ready to be allocated.

In order to identify live objects a search of the object graph is undertaken. The search starts from a set of 'root' objects which are objects that are guaranteed to be live, for example every thread is a root object. The search then find objects which are pointed to by the root set, and expands outwards until it has found all live objects. Here's a really nice pictorial representation, courtesy of Michael Triana



 

Parallel in the context of parallel scavenge means the collection is done by multiple threads running at the same time. This shouldn't be confused with ConcurrentGC, where the collector runs at the same time as, or interleaved with, the program. Parallel collection improves overall GC throughput by better using modern multicore CPUs. The parallelism is achieved by giving each thread a set of the roots to mark and a segment of the table of objects.

There are two survivor spaces, but only one of them is active at any point in time. They are collected in the same way as eden. The idea is that objects get copied into the active survivor space when they are promoted from eden. Then when its time to evacuate the space they are copied into the inactive survivor space. Once the active survivor space is completely evacuated the inactive space becomes active, and the active space becomes inactive. This is achieve by flipping the pointer to the beginning of the survivor space and means that all the dead objects in the survivor space can be freed at the cost of assigning to a single pointer.

Young Gen design and time tradeoffs

Since this involves only copying live objects and pointer changes the time taken to collect eden and survivor spaces is proportional to the amount of live objects. This is quite important since due to the generational hypothesis we know that most objects die young, and there's consequently no GC cost to freeing the memory associated with them.

The design of the survivor spaces is motivated by the idea that collecting objects when they are young is cheaper than doing a collection of the tenured space. Having objects continue to be collected in a hemispheric fashion for a few GC runs is helpful to the overall throughput.

Finally the fact that eden is organised into a single contiguous space makes object allocation cheap. A C program might back onto the 'malloc' command in order to allocate a block of memory, which involves traversing a list of free spaces in memory trying to find something that's big enough. When you use an arena allocator and consecutively allocate all you need to do is check there is enough free space and then increment a pointer by the size of the object.

Parallel Mark and Sweep

Objects that have survived a certain number of collections make their way into the tenured space. The number of times that they need to survive is referred to as the 'tenuring threshold'. Tenured Collections work somewhat differently to Eden, using an algorithm called mark and sweep. Each object has a mark bit associated with it. The marks are initially all set to false and as the object is reached during the graph search they're set to true.

The graph search that identifies live objects is similar to the search described for young generation. The difference is that instead of copying live objects, it simply marks them. After this it can go through the object table and free any object that isn't live. This process is done in parallel by several threads, each search a region of the heap.

Unfortunately this process of deleting objects that aren't live leaves the tenured space looking like Swiss Cheese. You get some used memory where objects live, and gaps in between where objects used to live. This kind of fragmentation isn't helpful for application performance because it makes it impossible to allocate objects that are bigger than the size of the holes.



 

Cheese after Mark and Sweep.

In order to reduce the Swiss Cheese problem the Parallel Mark/Sweep compacts the heap down to try and make live objects contiguously allocated at the start of the tenured space. After deletion it search areas of the tenured space in order to identify which have low occupancy and which have high occupancy. The live objects from lower occupancy regions are moved down towards regions that have higher occupancy. These are naturally at the lower end of memory from the previous compacting phase. The moving of objects in this phase is actually performed by the thread allocated to the destination region, rather than the source region.



 

Low occupancy cheese.

Summary

  • Parallel Scavenge splits heap up into 4 Spaces: eden, two survivor spaces and tenured.
  • Parallel Scavenge uses a parallel, copying collector to collector Eden and Survivor Spaces.
  • A different algorithm is used for the tenured space. This marks all live objects, deletes the dead objects and then compacts the space/
  • Parallel Scavenge has good throughput but it pauses the whole program when it runs.

In part three I'll look at how the CMS, or Concurrent-Mark-Sweep, collector works. Hopefully this post will be easier for those with dairy allergies to read.

  1. Technically there is an 'occupancy threshold' for each heap space - which defines how full the space is allowed to get before collection occurs.
  2. This copying algorithm is based on Cheney's algorithm
 

Concurrent Mark Sweep

This follows on from my previous two garbage collection blog posts:

  1. Overview of GC in Hotspot.
  2. Parallel Garbage Collectors.

Concurrent Mark Sweep

The parallel garbage collectors in Hotspot are designed to minimise the amount of time that the application spends undertaking garbage collection, which is termed throughput. This isn't an appropriate tradeoff for all applications - some require individual pauses to be short as well, which is known as a latency requirement.

The Concurrent Mark Sweep (CMS) collector is designed to be a lower latency collector than the parallel collectors. The key part of this design is trying to do part of the garbage collection at the same time as the application is running. This means that when the collector needs to pause the application's execution it doesn't need to pause for as long.

At this point you're probably thinking 'don't parallel and concurrent mean something fairly similar?' Well in the context of GC Parallel means "uses multiple threads to perform GC at the same time" and Concurrent means "the GC runs at the same time as the application is collecting".

Young Generational Collection

The young gen collector in CMS is called ParNew and it actually uses the same basic algorithm as the Parallel Scavenge collector in the parallel collectors, that I described previously.

This is still a different collector in terms of the hotspot codebase to Parallel Scavenge though because it needs to interleave its execution with the rest of CMS, and also implements a different internal API to Parallel Scavenge. Parallel Scavenge makes assumptions about which tenured collectors it works with - specifically ParOld and SerialOld. Bare in mind this also means that the young generational collector is stop the world.

Tenured Collection

As with the ParOld collector the CMS tenured collector uses a mark and sweep algorithm, in which live objects are marked and then dead objects are deleted. Deleted is really a strange term when it comes to memory management. The collector isn't actually deleting objects in the sense of blanking memory, its merely returning the memory associated with that object to the space that the memory system can allocate from - the freelist. Even though its termed a concurrent mark and sweep collector, not all phases run concurrently with the application's execution, two of them stop the world and four run concurrently.

How is GC triggered?

In ParOld garbage collection is triggered when you run out of space in the tenured heap. This approach works because ParOld simply pauses the application to collect. In order for the application to continue operating during a tenured collection, the CMS collector needs to start collecting when there is a still enough working space left in tenured.

So CMS starts based upon how full up tenured is - the idea is that the amount of free space left is your window of opportunity to run GC. This is known as the initiating occupancy fraction and is described in terms of how full the heap is, so a fraction of 0.7 gives you a window of 30% of your heap to run the CMS GC before you run out of heap.

Phases

Once the GC is triggered, the CMS algorithm consists of a series of phases run in sequence.

  1. Initial Mark - Pauses all application threads and marks all objects directly reachable from root objects as live. This phase stops the world.
  2. Concurrent Mark - Application threads are restarted. All live objects are transitively marked as reachable by following references from the objects marked in the initial mark.
  3. Concurrent Preclean - This phase looks at objects which have been updated or promoted during the concurrent mark or new objects that have been allocated during the concurrent mark. It updates the mark bit to denote whether these objects are live or dead. This phase may be run repeatedly until there is a specified occupancy ratio in Eden.
  4. Remark Since some objects may have been updated during the preclean phase its still necessary to do stop the world in order to process the residual objects. This phase does a retrace from the roots. It also processes reference objects, such as soft and weak references. This phase stops the world.
  5. Concurrent Sweep - This looks through the Ordinary Object Pointer (OOP) Table, which references all objects in the heap, and finds the dead objects. It then re-adds the memory allocated to those objects to its freelist. This is the list of spaces from which an object can be allocated.
  6. Concurrent Reset - Reset all internal data structures in order to be able to run CMS again in future.

Theoretically the objects marked during the preclean phase would get looked at during the next phase - remark - but the remark phase is stop the world, so the preclean phase exists to try and reduce remark pauses by doing part of the remark work concurrently. When CMS was originally added to HotSpot this phase didn't exist at all. It was added in Java 1.5 in order to address scenarios when a young generation scavenging collection causes a pause and is immediately followed by a remark. This remark also causes a pause, which combine to make a more painful pause. This is why remarks are triggered by an occupancy threshold in Eden - the goal is to schedule the remark phase halfway between young gen pauses.

The remark phases are also pausing, whilst the preclean isn't, which means that having precleans reduces the amount of time spent paused in GC.

Concurrent Mode Failures

Sometimes CMS is unable to meet the needs of the application and a stop-the-world Full GC needs to be run. This is called a concurrent mode failure, and usually results in a long pause. A concurrent mode failure happens when there isn't enough space in tenured to promote an object. There are two causes for this:

  • An object is promoted that is too large to fit into any contiguous space in memory.
  • There isn't enough space in tenured to account for the rate of live objects being promoted.

This might happen because the concurrent collection is unable to free space fast enough given the object promotion rates or because the continued use of the CMS collector has resulted in a fragmented heap and there's no individual space large enough to promote an object into. In order to properly 'defrag' the tenured heap space a full GC is required.

Permgen

CMS doesn't collect permgen spaces by default, and requires the ?XX:+CMSClassUnloadingEnabled flag enabled in order to do so. If, whilst using CMS, you run out of permgen space without this flag switched on it will trigger a Full GC. Furthermore permgen space can hold references into normal heap via things like classloaders, which means that until you collect Permgen you may be leaking memory in regular heap. In Java 7 String constants from class files are also allocated in regular heap, instead of permgen, which reduces permgen consumption, but also adds to the set of object references coming into regular heap from permgen.

Floating Garbage

At the end of a CMS collection its possible for some objects to not have been deleted - this is called Floating Garbage. This happens when objects become de-referenced since the initial mark. The concurrent preclean and the remark phase ensure that all live objects are marked by looking at objects which have been created, mutated or promoted. If an object has become dereferenced between the initial mark and the remark phase then it would require a complete retrace of the entire object graph in order to find all dead objects. This is obviously very expensive, and the remark phase must be kept short since its a pausing phase.

This isn't necessarily a problem for users of CMS since the next run of the CMS collector will clean up this garbage.

Summary

Concurrent Mark and Sweep reduces the pause times observed in the parallel collector by performing some of the GC work at the same time as the application runs. It doesn't entirely remove the pauses, since part of its algorithm needs to pause the application in order to execute.

It took me a little longer than I had hoped to get round to writing this blog post - but if you want to know when my next post is published simply enter your email in the top right hand corner of this blog to subscribe by email.

 

G1: Garbage First

The G1 collector is the latest collector to be implemented in the hotspot JVM. It's been a supported collector ever since Java 7 Update 4. Its also been publicly stated by the Oracle GC Team that their hope for low pause GC is a fully realised G1. This post follows on from my previous garbage collection blog posts:

  1. Overview of GC in Hotspot.
  2. Parallel Garbage Collectors.
  3. Concurrent Mark Sweep.

The Problem: Large heaps mean Large Pause Times

The Concurrent Mark and Sweep (CMS) collector is the currently recommended low pause collector, but unfortunately its pause times scale with the amount of live objects in its tenured region. This means that whilst its relatively easy to get short GC Pauses with smaller heaps, but once you start using heaps in the 10s or 100s of Gigabytes the times start to ramp up.

CMS also doesn't "defrag" its heap so at some point in time you'll get a concurrent mode failure (CMF), triggering a full gc. Once you get into this full gc scenario you can expect a pause in the timeframe of roughly 1 second per Gigabyte of live objects. With CMS your 100GB heap can be a 1.5 minute GC Pause ticking time bomb waiting to happen ...



 

Good GC Tuning can address this problem, but sometimes it just pushes the problem down the road. A Concurrent Mode Failure and therefore a Full GC is inevitable on a long enough timeline unless you're in the tiny niche of people who deliberately avoid filling their tenured space.

G1 Heap Layout

The G1 Collector tries to separate the pause time of an individual collection from the overall size of the heap by splitting up the heap into different regions. Each region is of a fixed size, between 1MB and 32MB, and the JVM aims to create about 2000 regions in total.


You may recall from previous articles that the other collectors split the heap up into Eden, Survivor Space and Tenured memory pools. G1 retains the same categories of pools but instead of these being contiguous blocks of memory, each region is logically categorised into one of these pools.

There is also another type of region - the humongous region. These are designed to store objects which are bigger in size than most objects - for example a very long array. Any object which is bigger than 50% of the size of a region is stored in a humongous region. They work by taking multiple normal regions which are contiguously located in memory and treating them as a single logical region.




 
 

Remembered Sets

Of course there's little point in splitting the heap into regions if you are going to have to scan the entire heap to figure out which objects are marked live. The first step in achieving this is breaking down regions into 512 Byte segments called cards. Each card has a 1 byte entry in the card marking table.

Each region has an associated remembered set or RSet - which is the set of cards that have been written to. A card is in the remembered set if an object from another region stored within the card points to an object within this region.

Whenever the mutator writes to an object reference, a write barrier is used to update the remembered set. Under the hood the remembered set is split up into different collections so that different threads can operate without contention, but conceptually all collections are part of the same remembered set.

Concurrent Marking

In order to identify which heap objects are live G1 performs a mostly concurrent mark of live objects.

  • Marking Phase The goal of the marking phase is to figure out which objects within the heap are live. In order to store which objects are live, G1 uses a marking bitmap - which stores a single bit for every 64bits on the heap. All objects are traced from their roots, marking areas with live objects in the marking bitmap. This is mostly concurrent, but there is an Initial Marking Pause similar to CMS where the application is paused and the first level of children from the root objects are traced. After this completes the mutator threads restart. G1 needs to keep an up to date understanding of what is live in the heap, since the heap isn't being cleaned up in the same pause as the marking phase.
  • Remarking Phase The goal of the remarking phase is to bring the information from the marking phase about live objects up to date. The first thing to do is decide when to remark. Its triggered by a percentage of the heap being full. This is calculated by taking information from the marking phase and the number of allocations since then and which tells G1 whether its over the required percentage. G1 uses the aforementioned write barrier to take note of changes to the heap and store them in series of change buffers. The objects in the change buffer are marked in the marking bitmap concurrently. When the fill percentage is reached the mutator threads are paused again and the change buffers are processed, marking objects in change buffers live.
  • Cleanup Phase At this point G1 knows which objects are live. Since G1 focusses on regions which have the most free space available, its next step is to work out the free space in a given region by counting the live objects. This is calculated from the marking bitmap, and regions are sorted according to which regions are most likely to be beneficial to collect. Regions which are to be collected are stored in what's know as a collection set or CSet.

Evacuation

Similar to the approach taken by the hemispheric Young Generation in the Parallel GC and CMS collectors dead objects aren't collected. Instead live objects get evacuated from a region and the entire region is then considered free.

G1 is intelligent about how it reclaims living objects - it doesn't try to reclaim all living objects in a given cycle. It targets regions which are likely to reclaim as much space as possible and only evacuates those. It works out its target regions by calculating the proportion of live objects within a region and picking region with the lowest proportion of live objects.

Objects are evacuated into free regions, from multiple other regions. This means that G1 compacts the data when performing GC. This is operated on in parallel by multiple threads. The traditional 'Parallel GC' does this but CMS doesn't.

Similar to CMS and Parallel GC there is a concept of tenuring. That is to say that young objects become 'old' if they survive enough collections. This number is called the tenuring threshold. If a young generational region survives the tenuring threshold and retains enough live objects to avoid being evacuated then the region is promoted. First to be a survivor and eventually a tenured region. It is never evacuated.

Evacuation Failure

Unfortunately, G1 can still encounter a scenario similar to a Concurrent Mode Failure in which it falls back to a Stop the World Full GC. This is called an evacuation failure and happens when there aren't any regions which are free. No free regions means no where to evacuate objects.

Theoretically evacuation failures are less likely to happen in G1 than Concurrent Mode Failures are in CMS. This is because G1 compacts its regions on the fly rather than just waiting for a failure for compaction to occur.

Conclusions

Despite the compaction and efforts at low pauses G1 isn't a guaranteed win and any attempt to adopt it should be accompanied by objective and measurable performance targets and GC Log analysis. The methodology required is out of the scope of this blog post, but hopefully I will cover it in a future post.

Algorithmically there are overheads that G1 encounters that other Hotspot collectors don't. Notably the cost of maintaining remembered sets. Parallel GC is still the recommended throughput collector, and in many circumstances CMS copes better than G1.

Its too early to tell if G1 will be a big win over the CMS Collector, but in some situations its already providing benefits for developers who use it. Over time we'll see if the performance limitations of G1 are really G1 limits or whether the development team just needs more engineering effort to solve the problems that are there.

Thanks to John Oliver, Tim Monks and Martijn Verburg for reviewing drafts of this and previous GC articles.

  • 大小: 6.3 KB
  • 大小: 11.6 KB
  • 大小: 7 KB
  • 大小: 61.5 KB
  • 大小: 9.2 KB
  • 大小: 15.9 KB
  • 大小: 155.3 KB
  • 大小: 4.4 KB
  • 大小: 10.7 KB
分享到:
评论

相关推荐

    zz差分包

    在IT领域,垃圾回收(Garbage Collection,简称GC)是一项重要的自动内存管理技术,主要用于管理程序中的动态内存分配。在Java、.NET等编程语言中,垃圾回收机制是其内存管理的核心部分,它自动识别并释放不再使用的...

    东营市乡镇边界,矢量边界,shp格式

    矢量边界,行政区域边界,精确到乡镇街道,可直接导入arcgis使用

    Java SSM 商户管理系统 客户管理 库存管理 销售报表 项目源码 本商品卖的是源码,合适的地方.zip

    毕业设计

    075.JSP+SQL宿舍管理系统.zip

    毕业设计

    经验贝叶斯EB的简单例子

    经验贝叶斯EB的简单例子

    69页-智慧园区综合管理平台解决方案.pdf

    智慧园区,作为现代城市发展的新形态,旨在通过高度集成的信息化系统,实现园区的智能化管理与服务。该方案提出,利用智能手环、定制APP、园区管理系统及物联网技术,将园区的各类设施与设备紧密相连,形成一个高效、便捷、安全的智能网络。从智慧社区到智慧酒店,从智慧景区到智慧康养,再到智慧生态,五大应用板块覆盖了园区的每一个角落,为居民、游客及工作人员提供了全方位、个性化的服务体验。例如,智能手环不仅能实现定位、支付、求助等功能,还能监测用户健康状况,让科技真正服务于生活。而智慧景区的建设,更是通过大数据分析、智能票务、电子围栏等先进技术,提升了游客的游玩体验,确保了景区的安全有序。 尤为值得一提的是,方案中的智慧康养服务,展现了科技对人文关怀的深刻体现。通过智慧手环与传感器,自动感知老人身体状态,及时通知家属或医疗机构,有效解决了“空巢老人”的照护难题。同时,智慧生态管理系统的应用,实现了对大气、水、植被等环境要素的实时监测与智能调控,为园区的绿色发展提供了有力保障。此外,方案还提出了建立全域旅游营销平台,整合区域旅游资源,推动旅游业与其他产业的深度融合,为区域经济的转型升级注入了新的活力。 总而言之,这份智慧园区建设方案以其前瞻性的理念、创新性的技术和人性化的服务设计,为我们展示了一个充满智慧与活力的未来园区图景。它不仅提升了园区的运营效率和服务质量,更让科技真正融入了人们的生活,带来了前所未有的便捷与舒适。对于正在规划或实施智慧园区建设的决策者而言,这份方案无疑提供了一份宝贵的参考与启示,激发了他们对于未来智慧生活的无限遐想与憧憬。

    数学建模相关主题资源2

    数学建模相关主题资源2

    SQL编程语言在数据科学领域的面试技巧及核心功能解析

    内容概要:本文围绕SQL在求职和实际工作中的应用展开,详细解析了SQL的重要性及其在不同行业中不可替代的地位。文章首先强调了SQL作为“一切数据工作的起点”,是数据分析、数据挖掘等领域必不可少的技能,并介绍了SQL与其他编程语言在就业市场的对比情况。随后重点探讨了SQL在面试过程中可能出现的挑战与应对策略,具体涉及到询问澄清问题、正确选择JOIN语句类型、恰当使用GROUP BY及相关过滤条件的区别、理解和运用窗口函数等方面,并给出了详细的实例和技巧提示。另外提醒面试者要注意重复值和空值等问题,倡导与面试官及时沟通。文中引用IEEE Spectrum编程语言排行榜证明了SQL不仅广泛应用于各行各业,在就业市场上也最受欢迎。 适用人群:从事或打算转入数据科学领域(包括但不限于数据分析师、数据科学家、数据工程师等职业方向),并对掌握和深入理解SQL有一定需求的专业人士,尤其是正准备涉及SQL相关技术面试的求职者。 使用场景及目标:帮助用户明确在面对复杂的SQL查询题目时能够更加灵活应对,提高解题效率的同时确保准确性;同时让用户意识到SQL不仅仅是简单的数据库查询工具,而是贯穿整个数据处理流程的基础能力之一,进而激发他们进一步探索的热情。 其他说明:SQL在性能方面优于Excel尤其适用于大规模数据操作;各知名企业仍将其视为标准数据操作手段。此外还提供了对初学者友好的建议,针对留学生普遍面临的难题如零散的学习资料、昂贵且效果不佳的付费教程以及难以跟上的纯英教学视频给出了改进的方向。

    COMSOL仿真揭示石墨烯临界耦合光吸收特性:费米能级调控下的光学性能探究,COMSOL仿真揭示石墨烯临界耦合光吸收特性:费米能级调控下的光学性能探究,COMSOL 准 BIC控制石墨烯临界耦合光吸收

    COMSOL仿真揭示石墨烯临界耦合光吸收特性:费米能级调控下的光学性能探究,COMSOL仿真揭示石墨烯临界耦合光吸收特性:费米能级调控下的光学性能探究,COMSOL 准 BIC控制石墨烯临界耦合光吸收。 COMSOL 光学仿真,石墨烯,光吸收,费米能级可调下图是仿真文件截图,所见即所得。 ,COMSOL; 准BIC; 石墨烯; 临界耦合光吸收; 光学仿真; 费米能级可调。,COMSOL仿真:石墨烯光吸收的BIC控制与费米能级调节

    Labview与Proteus串口仿真下的温度采集与报警系统:Keil单片机程序及全套视频源码解析,Labview与Proteus串口仿真温度采集及上位机报警系统实战教程:设定阈值的Keil程序源码分

    Labview与Proteus串口仿真下的温度采集与报警系统:Keil单片机程序及全套视频源码解析,Labview与Proteus串口仿真温度采集及上位机报警系统实战教程:设定阈值的Keil程序源码分享,labview 和proteus 联合串口仿真 温度采集 上位机报警 设定阈值单片机keil程序 整套视频仿真源码 ,关键词:LabVIEW;Proteus;串口仿真;温度采集;上位机报警;阈值设定;Keil程序;视频仿真源码。,LabVIEW与Proteus联合串口仿真:温度采集与报警系统,Keil程序与阈值设定全套视频源码

    整车性能目标书:涵盖燃油车、混动车及纯电动车型的十六个性能模块目标定义模板与集成开发指南,整车性能目标书:涵盖燃油车、混动车及纯电动车型的十六个性能模块目标定义模板与集成开发指南,整车性能目标书,汽车

    整车性能目标书:涵盖燃油车、混动车及纯电动车型的十六个性能模块目标定义模板与集成开发指南,整车性能目标书:涵盖燃油车、混动车及纯电动车型的十六个性能模块目标定义模板与集成开发指南,整车性能目标书,汽车性能目标书,十六个性能模块目标定义模板,包含燃油车、混动车型及纯电动车型。 对于整车性能的集成开发具有较高的参考价值 ,整车性能目标书;汽车性能目标书;性能模块目标定义模板;燃油车;混动车型;纯电动车型;集成开发;参考价值,《汽车性能模块化目标书:燃油车、混动车及纯电动车的集成开发参考》

    面板数据熵值法Stata代码( 附样本数据和结果).rar

    熵值法stata代码(含stata代码+样本数据) 面板熵值法是一种在多指标综合评价中常用的数学方法,主要用于对不同的评价对象进行量化分析,以确定各个指标在综合评价中的权重。该方法结合了熵值理论和面板数据分析,能够有效地处理包含多个指标的复杂数据。

    “电子电路”仿真资源(Multisim、Proteus、PCB等)

    “电子电路”仿真资源(Multisim、Proteus、PCB等)

    107_xee_water_consumption.txt

    在 GEE(Google Earth Engine)中,XEE 包是一个用于处理和分析地理空间数据的工具。以下是对 GEE 中 XEE 包的具体介绍: 主要特性 地理数据处理:提供强大的函数和工具,用于处理遥感影像和其他地理空间数据。 高效计算:利用云计算能力,支持大规模数据集的快速处理。 可视化:内置可视化工具,方便用户查看和分析数据。 集成性:可以与其他 GEE API 和工具无缝集成,支持多种数据源。 适用场景 环境监测:用于监测森林砍伐、城市扩展、水体变化等环境问题。 农业分析:分析作物生长、土地利用变化等农业相关数据。 气候研究:研究气候变化对生态系统和人类活动的影响。

    C++指针与内存管理详解:避免常见错误及最佳实践

    内容概要:本文介绍了C++编程中常见指针错误及其解决方案,并涵盖了模板元编程的基础知识和发展趋势,强调了高效流操作的最新进展——std::spanstream。文章通过一系列典型错误解释了指针的安全使用原则,强调指针初始化、内存管理和引用安全的重要性。随后介绍了模板元编程的核心特性,展示了编译期计算、类型萃取等高级编程技巧的应用场景。最后,阐述了C++23中引入的新特性std::spanstream的优势,对比传统流处理方法展现了更高的效率和灵活性。此外,还给出了针对求职者的C++技术栈学习建议,涵盖了语言基础、数据结构与算法及计算机科学基础领域内的多项学习资源与实战练习。 适合人群:正在学习C++编程的学生、从事C++开发的技术人员以及其他想要深入了解C++语言高级特性的开发者。 使用场景及目标:帮助读者掌握C++中的指针规则,预防潜在陷阱;介绍模板元编程的相关技术和优化方法;使读者理解新引入的标准库组件,提高程序性能;引导C++学习者按照有效的路径规划自己的技术栈发展路线。 阅读建议:对于指针部分的内容,应当结合实际代码样例反复实践,以便加深理解和记忆;在研究模板元编程时,要从简单的例子出发逐步建立复杂模型的理解能力,培养解决抽象问题的能力;而对于C++23带来的变化,则可以通过阅读官方文档并尝试最新标准特性来加深印象;针对求职准备,应结合个人兴趣和技术发展方向制定合理的学习计划,并注重积累高质量的实际项目经验。

    Java读写FM1208CPU卡源码

    JNA、JNI, Java两种不同调用DLL、SO动态库方式读写FM1208 CPU卡示例源码,包括初始化CPU卡、创建文件、修改文件密钥、读写文件数据等操作。支持Windows系统、支持龙芯Mips、LoongArch、海思麒麟鲲鹏飞腾Arm、海光兆芯x86_Amd64等架构平台的国产统信、麒麟等Linux系统编译运行,内有jna-4.5.0.jar包,vx13822155058 qq954486673

    Linux系统入门到精通:从基础命令到服务管理和日志解析

    内容概要:本文全面介绍了Linux系统的各个方面,涵盖入门知识、基础操作、进阶技巧以及高级管理技术。首先概述了Linux的特点及其广泛的应用领域,并讲解了Linux环境的搭建方法(如使用虚拟机安装CentOS),随后深入剖析了一系列常用命令和快捷键,涉及文件系统管理、用户和权限设置、进程和磁盘管理等内容。此外,还讨论了服务管理的相关指令(如nohup、systemctl)以及日志记录和轮替的最佳实践。这不仅为初学者提供了一个完整的知识框架,也为中级和高级用户提供深入理解和优化系统的方法。 适合人群:适用于有意深入了解Linux系统的学生和专业技术人员,特别是需要掌握服务器运维技能的人群。 使用场景及目标:本文适合初次接触Linux的操作员了解基本概念;也适合作为培训教材,指导学生逐步掌握各项技能。对于有一定经验的技术人员而言,则可以帮助他们巩固基础知识,并探索更多的系统维护和优化可能性。 阅读建议:建议按照文章结构循序渐进地学习相关内容,尤其是结合实际练习操作来加深记忆和理解。遇到复杂的问题时可以通过查阅官方文档或在线资源获得更多帮助。

    企业绩效考核制度详解:运维部门绩效管理流程规范及其应用

    内容概要:本文档详细介绍了企业在规范运维部门绩效管理过程中所建立的一套绩效考核制度。首先阐述了绩效考核制度设立的目的为确保绩效目标得以衡量与追踪,并确保员工与公司共同成长与发展。其次规定范围覆盖公司所有在职员工,并详细列明了从总经理到一线员工在内的不同角色的职责范围。再则描述了完整的绩效工作流程,即从年初开始制定绩效管理活动计划,经过与每个员工制定具体的绩效目标,在绩效考核周期之内对员工的工作进展和问题解决状况进行持续的监督跟进,并且在每周期结束前完成员工绩效的评估和反馈工作,同时利用绩效评估结果对员工作出保留或异动的相关决定,最后进行绩效管理活动总结以为来年提供参考。此外还强调了整个过程中必要的相关文档保存,如员工绩效评估表。 适合人群:企业管理层,HR专业人士及对现代企业内部运营管理感兴趣的读者。 使用场景及目标:①管理层需要理解如何规范和有效实施企业内部绩效管理,以提高公司运营效率和员工满意度;②HR人士可以通过参考此文档来优化自己公司的绩效管理体系;③对企业和组织管理有兴趣的研究员亦可借鉴。 阅读建议:读者应重点关注各个层级管理者和员工在整个流程中的角色和责任,以期更好地理解

    基于MATLAB Simulink的LCL三相并网逆变器仿真模型:采用交流电流内环PR控制与SVPWM-PWM波控制研究,基于MATLAB Simulink的LCL三相并网逆变器仿真模型研究:采用比例

    基于MATLAB Simulink的LCL三相并网逆变器仿真模型:采用交流电流内环PR控制与SVPWM-PWM波控制研究,基于MATLAB Simulink的LCL三相并网逆变器仿真模型研究:采用比例谐振控制与交流SVPWM控制策略及参考文献解析,LCL_Three_Phase_inverter:基于MATLAB Simulink的LCL三相并网逆变器仿真模型,交流电流内环才用PR(比例谐振)控制,PWM波采用SVPWM控制,附带对应的参考文献。 仿真条件:MATLAB Simulink R2015b,前如需转成低版本格式请提前告知,谢谢。 ,LCL三相并网逆变器; LCL_Three_Phase_inverter; MATLAB Simulink; PR控制; SVPWM控制; 仿真模型; 参考文献; 仿真条件; R2015b版本,基于PR控制与SVPWM的LCL三相并网逆变器Simulink仿真模型研究

    内点法求解标准节点系统最优潮流计算的稳定程序,注释清晰,通用性强,内点法用于标准节点系统的最优潮流计算:稳定、通用且注释清晰的matlab程序,内点法最优潮流程序matlab 采用内点法对14标准节点

    内点法求解标准节点系统最优潮流计算的稳定程序,注释清晰,通用性强,内点法用于标准节点系统的最优潮流计算:稳定、通用且注释清晰的matlab程序,内点法最优潮流程序matlab 采用内点法对14标准节点系统进行最优潮流计算,程序运行稳定,注释清楚,通用性强 ,内点法; 最优潮流程序; MATLAB; 14标准节点系统; 稳定运行; 清晰注释; 通用性强。,Matlab内点法最优潮流程序:稳定高效,通用性强,适用于14节点系统

Global site tag (gtag.js) - Google Analytics