Bottlenecks limit application performance and can be caused by hardware, software, or network resources. Identifying bottlenecks in complex J2EE applications requires various tools. The process involves running load tests using diagnostic tools to identify bottleneck layers and components, then using profilers to debug problematic code. Monitoring application server heap usage and server resource consumption also helps identify bottlenecks.